From 664845a99b3f3fcb1cd08f2d9d5eeb8e2cf9d0f1 Mon Sep 17 00:00:00 2001 From: Lucas Clemente Vella Date: Thu, 6 Jul 2023 20:34:11 +0100 Subject: [PATCH 1/3] Making std optional. --- Cargo.lock | 22 +++++++++++++++++++++- Cargo.toml | 10 ++++++++-- src/algorithms/div/knuth.rs | 3 ++- src/algorithms/div/reciprocal.rs | 2 +- src/algorithms/div/small.rs | 1 + src/algorithms/gcd/matrix.rs | 2 +- src/algorithms/gcd/mod.rs | 2 +- src/algorithms/mul.rs | 1 + src/algorithms/mul_redc.rs | 1 + src/base_convert.rs | 1 + src/bit_arr.rs | 2 +- src/bytes.rs | 2 +- src/div.rs | 1 + src/from.rs | 6 ++++++ src/lib.rs | 14 +++++++++++--- src/modular.rs | 3 ++- src/pow.rs | 2 +- src/string.rs | 7 ++++--- src/support/arbitrary.rs | 3 ++- src/utils.rs | 2 ++ 20 files changed, 69 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ec4cd53..e0d7ad1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1687,7 +1687,7 @@ dependencies = [ "serde_json", "smallvec", "sqlx-core", - "thiserror", + "thiserror-core", "valuable", "zeroize", ] @@ -2029,6 +2029,26 @@ dependencies = [ "thiserror-impl", ] +[[package]] +name = "thiserror-core" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" +dependencies = [ + "thiserror-core-impl", +] + +[[package]] +name = "thiserror-core-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "thiserror-impl" version = "1.0.40" diff --git a/Cargo.toml b/Cargo.toml index 293c6aab..02ede078 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,12 +15,14 @@ license = "MIT" members = ["ruint-macro"] [features] -default = [] +default = ["std"] bench = ["dep:criterion", "proptest", "rand"] dyn = ["dep:smallvec"] generic_const_exprs = [] postgres = ["dep:postgres-types", "dep:bytes"] sqlx = ["dep:sqlx-core"] +# no_std requires nightly rust due to use of #![feature(error_in_core)] (issue #103765) +std = ["thiserror/std"] [[bench]] name = "criterion" @@ -51,7 +53,11 @@ smallvec = { version = "1.8.0", optional = true, features = [ "union" ] } # for # HACK: (BLOCKED) sqlx requires a runtime to be specified. # sqlx-core = { version = "0.6", optional = true, features = [ "runtime-tokio-native-tls" ] } -thiserror = "1.0" +# thiserror does not support no-std, the PR to support it is +# https://github.com/dtolnay/thiserror/pull/211, but I don't think it will be +# merged until https://github.com/rust-lang/rust/issues/103765 is stabilized. +# So, the forked thiserror with no-std support is being used instead. +thiserror = { version = "1.0", default-features = false, package = "thiserror-core" } valuable = { version = "0.1.0", optional = true } zeroize = { version = "1.5", optional = true } diff --git a/src/algorithms/div/knuth.rs b/src/algorithms/div/knuth.rs index c7f8399e..af9c6b43 100644 --- a/src/algorithms/div/knuth.rs +++ b/src/algorithms/div/knuth.rs @@ -194,11 +194,12 @@ mod tests { add::{cmp, sbb_n}, addmul, }; + use alloc::{vec, vec::Vec}; + use core::cmp::Ordering; use proptest::{ collection, num, proptest, strategy::{Just, Strategy}, }; - use std::cmp::Ordering; // Basic test without exceptional paths #[test] diff --git a/src/algorithms/div/reciprocal.rs b/src/algorithms/div/reciprocal.rs index e84e7493..7b6cb6b3 100644 --- a/src/algorithms/div/reciprocal.rs +++ b/src/algorithms/div/reciprocal.rs @@ -6,7 +6,7 @@ //! [new]: https://gmplib.org/list-archives/gmp-devel/2019-October/005590.html #![allow(dead_code, clippy::cast_possible_truncation, clippy::cast_lossless)] -use std::num::Wrapping; +use core::num::Wrapping; pub use self::{reciprocal_2_mg10 as reciprocal_2, reciprocal_mg10 as reciprocal}; diff --git a/src/algorithms/div/small.rs b/src/algorithms/div/small.rs index 00d1918b..7efb9ffb 100644 --- a/src/algorithms/div/small.rs +++ b/src/algorithms/div/small.rs @@ -280,6 +280,7 @@ pub fn div_3x2_mg10(u21: u128, u0: u64, d: u128, v: u64) -> (u64, u128) { mod tests { use super::*; use crate::algorithms::addmul; + use alloc::{format, vec}; use proptest::{ collection, num::{u128, u64}, diff --git a/src/algorithms/gcd/matrix.rs b/src/algorithms/gcd/matrix.rs index 10355433..b92736e2 100644 --- a/src/algorithms/gcd/matrix.rs +++ b/src/algorithms/gcd/matrix.rs @@ -333,12 +333,12 @@ impl Matrix { mod tests { use super::*; use crate::{const_for, nlimbs}; + use alloc::str::FromStr; use core::{ cmp::{max, min}, mem::swap, }; use proptest::{proptest, test_runner::Config}; - use std::str::FromStr; fn gcd(mut a: u128, mut b: u128) -> u128 { while b != 0 { diff --git a/src/algorithms/gcd/mod.rs b/src/algorithms/gcd/mod.rs index 60f061ef..db902ef7 100644 --- a/src/algorithms/gcd/mod.rs +++ b/src/algorithms/gcd/mod.rs @@ -193,7 +193,7 @@ mod tests { #[test] fn test_gcd_one() { - use std::str::FromStr; + use alloc::str::FromStr; const BITS: usize = 129; const LIMBS: usize = nlimbs(BITS); type U = Uint; diff --git a/src/algorithms/mul.rs b/src/algorithms/mul.rs index c1dfb7b3..9c61348c 100644 --- a/src/algorithms/mul.rs +++ b/src/algorithms/mul.rs @@ -281,6 +281,7 @@ pub fn submul_nx1(lhs: &mut [u64], a: &[u64], b: u64) -> u64 { #[cfg(test)] mod tests { use super::*; + use alloc::vec; use proptest::{collection, num::u64, proptest}; #[test] diff --git a/src/algorithms/mul_redc.rs b/src/algorithms/mul_redc.rs index c5529861..180577e8 100644 --- a/src/algorithms/mul_redc.rs +++ b/src/algorithms/mul_redc.rs @@ -1,4 +1,5 @@ use super::addmul; +use alloc::vec; use core::iter::zip; /// See Handbook of Applied Cryptography, Algorithm 14.32, p. 601. diff --git a/src/base_convert.rs b/src/base_convert.rs index 9bc059f4..86714401 100644 --- a/src/base_convert.rs +++ b/src/base_convert.rs @@ -1,4 +1,5 @@ use crate::Uint; +use alloc::vec::Vec; use thiserror::Error; /// Error for [`from_base_le`][Uint::from_base_le] and diff --git a/src/bit_arr.rs b/src/bit_arr.rs index 8c31950e..3d09d3dd 100644 --- a/src/bit_arr.rs +++ b/src/bit_arr.rs @@ -1,10 +1,10 @@ use crate::{ParseError, Uint}; +use alloc::{borrow::Cow, vec::Vec}; use core::ops::{ BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Index, Not, Shl, ShlAssign, Shr, ShrAssign, }; use derive_more::{From, FromStr, Into}; -use std::borrow::Cow; /// A newtype wrapper around [`Uint`] that restricts operations to those /// relevant for bit arrays. diff --git a/src/bytes.rs b/src/bytes.rs index 18240784..75e9f63f 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -5,12 +5,12 @@ use crate::{ utils::{trim_end_slice, trim_end_vec}, Uint, }; +use alloc::{borrow::Cow, vec::Vec}; use core::{ mem::size_of_val, ptr::{addr_of, addr_of_mut}, slice, }; -use std::borrow::Cow; // OPT: *_to_smallvec to avoid allocation. diff --git a/src/div.rs b/src/div.rs index ff72b91d..adb7c557 100644 --- a/src/div.rs +++ b/src/div.rs @@ -82,6 +82,7 @@ impl_bin_op!(Rem, rem, RemAssign, rem_assign, wrapping_rem); pub mod tests { use super::*; use crate::{const_for, nlimbs}; + use alloc::format; use proptest::{prop_assume, proptest}; #[test] diff --git a/src/from.rs b/src/from.rs index 0768d319..ed9bafb3 100644 --- a/src/from.rs +++ b/src/from.rs @@ -415,6 +415,7 @@ impl_from_signed_int!(i64, u64); impl_from_signed_int!(i128, u128); impl_from_signed_int!(isize, usize); +#[cfg(feature = "std")] impl TryFrom for Uint { type Error = ToUintError; @@ -483,6 +484,7 @@ impl TryFrom for Uint { } } +#[cfg(feature = "std")] impl TryFrom for Uint { type Error = ToUintError; @@ -601,12 +603,14 @@ impl TryFrom<&Uint> for u128 // Convert Uint to floating point // +#[cfg(feature = "std")] impl From> for f32 { fn from(value: Uint) -> Self { Self::from(&value) } } +#[cfg(feature = "std")] impl From<&Uint> for f32 { /// Approximate single precision float. /// @@ -618,12 +622,14 @@ impl From<&Uint> for f32 { } } +#[cfg(feature = "std")] impl From> for f64 { fn from(value: Uint) -> Self { Self::from(&value) } } +#[cfg(feature = "std")] impl From<&Uint> for f64 { /// Approximate double precision float. /// diff --git a/src/lib.rs b/src/lib.rs index 9b0ab737..ec3b01cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +#![cfg_attr(not(feature = "std"), no_std, feature(error_in_core))] #![doc = include_str!("../Readme.md")] #![doc(issue_tracker_base_url = "https://github.com/recmo/uint/issues/")] #![warn(clippy::all, clippy::pedantic, clippy::cargo, clippy::nursery)] @@ -26,6 +27,8 @@ // Nightly only feature flag to enable the `unlikely` compiler hint. #![cfg_attr(has_core_intrinsics, feature(core_intrinsics))] +extern crate alloc; + // Workaround for proc-macro `uint!` in this crate. // See extern crate self as ruint; @@ -42,16 +45,21 @@ mod const_for; mod div; mod from; mod gcd; -mod log; mod modular; mod mul; -mod pow; -mod root; mod special; mod string; mod support; mod uint_dyn; mod utils; +// The following math operations are disable due to lack of some floating point +// functions in core. See issue https://github.com/rust-lang/rust/issues/50145 +#[cfg(feature = "std")] +mod log; +#[cfg(feature = "std")] +mod pow; +#[cfg(feature = "std")] +mod root; #[cfg(all(feature = "dyn", feature = "unstable"))] #[doc(inline)] diff --git a/src/modular.rs b/src/modular.rs index 85f8baa8..3ac3e461 100644 --- a/src/modular.rs +++ b/src/modular.rs @@ -1,4 +1,5 @@ use crate::{algorithms, nlimbs, Uint}; +use alloc::vec; // FEATURE: sub_mod, neg_mod, inv_mod, div_mod, root_mod // See @@ -169,6 +170,7 @@ impl Uint { mod tests { use super::*; use crate::{aliases::U64, const_for, nlimbs}; + use alloc::format; use core::cmp::min; use proptest::{prop_assume, proptest, test_runner::Config}; @@ -289,7 +291,6 @@ mod tests { // TODO: Test for larger (>= m) values of a, b. let expected = a.mul_mod(b, m).mul_mod(r, m); - assert_eq!(ar.mul_redc(br, m, inv), expected); } }); diff --git a/src/pow.rs b/src/pow.rs index 850a848a..4359e6e6 100644 --- a/src/pow.rs +++ b/src/pow.rs @@ -166,8 +166,8 @@ impl Uint { mod tests { use super::*; use crate::{const_for, nlimbs}; + use core::iter::repeat; use proptest::proptest; - use std::iter::repeat; #[test] fn test_pow2_shl() { diff --git a/src/string.rs b/src/string.rs index 67952c5d..c8302fc4 100644 --- a/src/string.rs +++ b/src/string.rs @@ -1,8 +1,8 @@ use crate::{base_convert::BaseConvertError, utils::rem_up, Uint}; -use core::fmt::{ - Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex, +use core::{ + fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex}, + str::FromStr, }; -use std::str::FromStr; use thiserror::Error; // FEATURE: Respect width parameter in formatters. @@ -186,6 +186,7 @@ impl FromStr for Uint { #[cfg(test)] mod tests { use super::*; + use alloc::{format, string::ToString}; use proptest::proptest; #[allow(clippy::unreadable_literal)] diff --git a/src/support/arbitrary.rs b/src/support/arbitrary.rs index b71b0be1..245ee198 100644 --- a/src/support/arbitrary.rs +++ b/src/support/arbitrary.rs @@ -32,7 +32,8 @@ impl<'a, const BITS: usize, const LIMBS: usize> Arbitrary<'a> for Uint usize { From 284c642d3195c941906007cc10432e86b8bde307 Mon Sep 17 00:00:00 2001 From: Lucas Clemente Vella Date: Fri, 7 Jul 2023 16:32:20 +0100 Subject: [PATCH 2/3] Updating documentation w.r.t. to no_std support. --- Changelog.md | 1 + Readme.md | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index 6dabf5a7..bdacb868 100644 --- a/Changelog.md +++ b/Changelog.md @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Support for `#![no_std]` builds with the new `std` feature. - Support `bn-rs`, `serde` and `uint!` for `Bits` ### Fixed diff --git a/Readme.md b/Readme.md index a976816e..aae1254a 100644 --- a/Readme.md +++ b/Readme.md @@ -70,6 +70,12 @@ it in the stable version. There are a few more subtle issues that make this less ideal than it appears. It also looks like it may take some time before these nightly features are stabilized. +Also, on nightly you may disable the `std` feature for `#![no_std]` support. +Nightly is required until the stabilization of `error_in_core` (Rust issue +[#103765][r103765]), moving the standard `Error` trait to `core`. + +[r103765]: https://github.com/rust-lang/rust/issues/103765 + ## Examples ```rust @@ -112,8 +118,21 @@ Note that since `B` is a valid hexadecimal digit there can be ambiguity. To less ## Feature flags -There is support for a number of crates. These are enabled by setting the identically -named feature flag. +The only feature enabled by default is `std`. Disabling it is only supported on +nightly, and removes the dependency on the `std` crate, allowing this crate to +be used on `#![no_std]` projects. Due to limited support for floating point +operations in `core` (see Rust issue [#50145][r50145]), without `std` the +following functionalities are disabled: + * module `log` + * module `pow` + * module `root` + * trait implementation `From` + * trait implementation `From` + +[r50145]: https://github.com/rust-lang/rust/issues/50145 + +There is optional support for a number of crates. These are enabled by setting +the identically named feature flag. * `unstable` Enable sem-ver unstable features. * [`rand`](https://docs.rs/rand): Implements sampling from the [`Standard`](https://docs.rs/rand/latest/rand/distributions/struct.Standard.html) distribution, i.e. [`rng.gen()`](https://docs.rs/rand/latest/rand/trait.Rng.html#method.gen). From 72868a8beb62990f66fea32d79899c8251023ec0 Mon Sep 17 00:00:00 2001 From: Lucas Clemente Vella Date: Fri, 7 Jul 2023 21:58:12 +0100 Subject: [PATCH 3/3] Passing down std feature to crates that supports it. --- Cargo.toml | 8 ++++---- src/support/rlp.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 02ede078..cf636cfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ generic_const_exprs = [] postgres = ["dep:postgres-types", "dep:bytes"] sqlx = ["dep:sqlx-core"] # no_std requires nightly rust due to use of #![feature(error_in_core)] (issue #103765) -std = ["thiserror/std"] +std = ["thiserror/std", "proptest?/std", "proptest?/alloc", "primitive-types?/std", "rlp?/std"] [[bench]] name = "criterion" @@ -41,12 +41,12 @@ fastrlp = { version = "0.3.1", optional = true } num-bigint = { version = "0.4.3", optional = true } parity-scale-codec = { version = "3.2.1", optional = true, features = [ "max-encoded-len" ] } postgres-types = { version = "0.2.3", optional = true } -primitive-types = { version = "<1", optional = true } -proptest = { version = "1.0", optional = true } +primitive-types = { version = "<1", default-features = false, optional = true } +proptest = { version = "1.0", default-features = false, optional = true } pyo3 = { version = "0.18.3", optional = true } quickcheck = { version = "1.0", optional = true } rand = { version = "0.8.5", optional = true } -rlp = { version = "0.5.1", optional = true } +rlp = { version = "0.5.1", default-features = false, optional = true } ruint-macro = { version = "1.0.2", path = "./ruint-macro" } serde = { version = "1.0", optional = true } smallvec = { version = "1.8.0", optional = true, features = [ "union" ] } # for UintDyn diff --git a/src/support/rlp.rs b/src/support/rlp.rs index 742e7011..a4560f73 100644 --- a/src/support/rlp.rs +++ b/src/support/rlp.rs @@ -3,8 +3,8 @@ #![cfg_attr(has_doc_cfg, doc(cfg(feature = "rlp")))] use crate::{Bits, Uint}; +use core::cmp::Ordering; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; -use std::cmp::Ordering; /// Allows a [`Uint`] to be serialized as RLP. ///