From ba15044897e52e4fe23ea3eeeab1b9bf8881a2ce Mon Sep 17 00:00:00 2001 From: Ralph Tandetzky Date: Fri, 10 May 2024 01:13:05 +0200 Subject: [PATCH 1/8] Fixed incorrect formulas for coefficients. This concerns only the comments for big integer multiplication where the formulas for the coefficients w0..w4 are explicitly listed. These were not completely correct. --- src/biguint/multiplication.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/biguint/multiplication.rs b/src/biguint/multiplication.rs index c97c7e1a..e9d21384 100644 --- a/src/biguint/multiplication.rs +++ b/src/biguint/multiplication.rs @@ -369,9 +369,9 @@ fn mac3(mut acc: &mut [BigDigit], mut b: &[BigDigit], mut c: &[BigDigit]) { // in terms of its coefficients: // // w0 = w(0) - // w1 = w(0)/2 + w(1)/3 - w(-1) + w(2)/6 - 2*w(inf) + // w1 = w(0)/2 + w(1)/3 - w(-1) + w(-2)/6 - 2*w(inf) // w2 = -w(0) + w(1)/2 + w(-1)/2 - w(inf) - // w3 = -w(0)/2 + w(1)/6 + w(-1)/2 - w(1)/6 + // w3 = -w(0)/2 + w(1)/6 + w(-1)/2 - w(-2)/6 + 2*w(inf) // w4 = w(inf) // // This particular sequence is given by Bodrato and is an interpolation From f12e8129a17131b042f15cdb566be75da72045b9 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 10 May 2024 13:27:54 -0700 Subject: [PATCH 2/8] Commit to `alloc` as much as possible Since our MSRV is 1.60, and `alloc` was stabilized way back in 1.36, we don't need to be conditional about using it anymore. There are still a few places where we use `std` functionality, like `std::error::Error`, so that feature flag is still useful, but less than it used to be. --- src/bigint.rs | 3 ++- src/bigint/arbitrary.rs | 4 ++-- src/bigint/bits.rs | 2 +- src/bigint/convert.rs | 2 +- src/biguint.rs | 3 ++- src/biguint/arbitrary.rs | 4 ++-- src/biguint/convert.rs | 2 +- src/biguint/monty.rs | 2 +- src/biguint/serde.rs | 3 +-- src/biguint/shift.rs | 3 ++- src/lib.rs | 36 +++++++----------------------------- 11 files changed, 22 insertions(+), 42 deletions(-) diff --git a/src/bigint.rs b/src/bigint.rs index ffd457da..76b64fbb 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -1,7 +1,8 @@ // `Add`/`Sub` ops may flip from `BigInt` to its `BigUint` magnitude #![allow(clippy::suspicious_arithmetic_impl)] -use crate::std_alloc::{String, Vec}; +use alloc::string::String; +use alloc::vec::Vec; use core::cmp::Ordering::{self, Equal}; use core::default::Default; use core::fmt; diff --git a/src/bigint/arbitrary.rs b/src/bigint/arbitrary.rs index df66050e..6b809cae 100644 --- a/src/bigint/arbitrary.rs +++ b/src/bigint/arbitrary.rs @@ -1,8 +1,8 @@ use super::{BigInt, Sign}; +use crate::BigUint; #[cfg(feature = "quickcheck")] -use crate::std_alloc::Box; -use crate::BigUint; +use alloc::boxed::Box; #[cfg(feature = "quickcheck")] impl quickcheck::Arbitrary for BigInt { diff --git a/src/bigint/bits.rs b/src/bigint/bits.rs index 93cd24c4..ac4fe1de 100644 --- a/src/bigint/bits.rs +++ b/src/bigint/bits.rs @@ -3,8 +3,8 @@ use super::Sign::{Minus, NoSign, Plus}; use crate::big_digit::{self, BigDigit, DoubleBigDigit}; use crate::biguint::IntDigits; -use crate::std_alloc::Vec; +use alloc::vec::Vec; use core::cmp::Ordering::{Equal, Greater, Less}; use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign}; use num_traits::{ToPrimitive, Zero}; diff --git a/src/bigint/convert.rs b/src/bigint/convert.rs index f0c29c49..9c7ab55e 100644 --- a/src/bigint/convert.rs +++ b/src/bigint/convert.rs @@ -1,10 +1,10 @@ use super::Sign::{self, Minus, NoSign, Plus}; use super::{BigInt, ToBigInt}; -use crate::std_alloc::Vec; use crate::TryFromBigIntError; use crate::{BigUint, ParseBigIntError, ToBigUint}; +use alloc::vec::Vec; use core::cmp::Ordering::{Equal, Greater, Less}; use core::convert::TryFrom; use core::str::{self, FromStr}; diff --git a/src/biguint.rs b/src/biguint.rs index 41506055..a3bfdcd3 100644 --- a/src/biguint.rs +++ b/src/biguint.rs @@ -1,6 +1,7 @@ use crate::big_digit::{self, BigDigit}; -use crate::std_alloc::{String, Vec}; +use alloc::string::String; +use alloc::vec::Vec; use core::cmp; use core::cmp::Ordering; use core::default::Default; diff --git a/src/biguint/arbitrary.rs b/src/biguint/arbitrary.rs index 6fa91c0f..76099bc4 100644 --- a/src/biguint/arbitrary.rs +++ b/src/biguint/arbitrary.rs @@ -2,8 +2,8 @@ use super::{biguint_from_vec, BigUint}; use crate::big_digit::BigDigit; #[cfg(feature = "quickcheck")] -use crate::std_alloc::Box; -use crate::std_alloc::Vec; +use alloc::boxed::Box; +use alloc::vec::Vec; #[cfg(feature = "quickcheck")] impl quickcheck::Arbitrary for BigUint { diff --git a/src/biguint/convert.rs b/src/biguint/convert.rs index 18c74bb3..a81778c8 100644 --- a/src/biguint/convert.rs +++ b/src/biguint/convert.rs @@ -8,10 +8,10 @@ use super::division::{div_rem_digit, FAST_DIV_WIDE}; use super::multiplication::mac_with_carry; use crate::big_digit::{self, BigDigit}; -use crate::std_alloc::Vec; use crate::ParseBigIntError; use crate::TryFromBigIntError; +use alloc::vec::Vec; use core::cmp::Ordering::{Equal, Greater, Less}; use core::convert::TryFrom; use core::mem; diff --git a/src/biguint/monty.rs b/src/biguint/monty.rs index 484034e4..eeb0791e 100644 --- a/src/biguint/monty.rs +++ b/src/biguint/monty.rs @@ -1,4 +1,4 @@ -use crate::std_alloc::Vec; +use alloc::vec::Vec; use core::mem; use core::ops::Shl; use num_traits::One; diff --git a/src/biguint/serde.rs b/src/biguint/serde.rs index 1fadf16a..f0f792be 100644 --- a/src/biguint/serde.rs +++ b/src/biguint/serde.rs @@ -1,7 +1,6 @@ use super::{biguint_from_vec, BigUint}; -use crate::std_alloc::Vec; - +use alloc::vec::Vec; use core::{cmp, fmt, mem}; use serde::de::{SeqAccess, Visitor}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; diff --git a/src/biguint/shift.rs b/src/biguint/shift.rs index edcbc158..51483cd0 100644 --- a/src/biguint/shift.rs +++ b/src/biguint/shift.rs @@ -1,8 +1,9 @@ use super::{biguint_from_vec, BigUint}; use crate::big_digit; -use crate::std_alloc::{Cow, Vec}; +use alloc::borrow::Cow; +use alloc::vec::Vec; use core::mem; use core::ops::{Shl, ShlAssign, Shr, ShrAssign}; use num_traits::{PrimInt, Zero}; diff --git a/src/lib.rs b/src/lib.rs index b807fd20..e9d2a048 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,10 +60,10 @@ //! //! ## Features //! -//! The `std` crate feature is enabled by default, and is mandatory before Rust -//! 1.36 and the stabilized `alloc` crate. If you depend on `num-bigint` with -//! `default-features = false`, you must manually enable the `std` feature yourself -//! if your compiler is not new enough. +//! The `std` crate feature is enabled by default, which enables [`std::error::Error`] +//! implementations and some internal use of floating point approximations. This can be disabled by +//! depending on `num-bigint` with `default-features = false`. Either way, the `alloc` crate is +//! always required for heap allocation of the `BigInt`/`BigUint` digits. //! //! ### Random Generation //! @@ -87,35 +87,13 @@ #![warn(rust_2018_idioms)] #![no_std] -#[cfg(feature = "std")] -#[macro_use] -extern crate std; - -#[cfg(feature = "std")] -mod std_alloc { - pub(crate) use std::borrow::Cow; - #[cfg(feature = "quickcheck")] - pub(crate) use std::boxed::Box; - pub(crate) use std::string::String; - pub(crate) use std::vec::Vec; -} - -#[cfg(not(feature = "std"))] #[macro_use] extern crate alloc; -#[cfg(not(feature = "std"))] -mod std_alloc { - pub(crate) use alloc::borrow::Cow; - #[cfg(feature = "quickcheck")] - pub(crate) use alloc::boxed::Box; - pub(crate) use alloc::string::String; - pub(crate) use alloc::vec::Vec; -} +#[cfg(feature = "std")] +extern crate std; use core::fmt; -#[cfg(feature = "std")] -use std::error::Error; #[macro_use] mod macros; @@ -176,7 +154,7 @@ impl fmt::Display for ParseBigIntError { } #[cfg(feature = "std")] -impl Error for ParseBigIntError { +impl std::error::Error for ParseBigIntError { fn description(&self) -> &str { self.__description() } From 52175ce0612462765a2932d9d86f57237d27eba6 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 10 May 2024 14:55:19 -0700 Subject: [PATCH 3/8] Add feature cfgs for docs.rs --- .github/workflows/ci.yaml | 12 +++++++++++- Cargo.toml | 1 + src/bigint.rs | 8 ++------ src/bigint/arbitrary.rs | 4 ++++ src/bigint/serde.rs | 3 +++ src/bigrand.rs | 2 ++ src/biguint.rs | 8 ++------ src/biguint/arbitrary.rs | 4 ++++ src/biguint/serde.rs | 3 +++ src/lib.rs | 20 +++++++++++++++++--- 10 files changed, 49 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8ddca545..ede5aaed 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -63,12 +63,22 @@ jobs: components: rustfmt - run: cargo fmt --all --check + doc: + name: Docs.rs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo doc --features std,serde,rand,quickcheck,arbitrary + env: + RUSTDOCFLAGS: --cfg docsrs + # One job that "summarizes" the success state of this pipeline. This can then be added to branch # protection, rather than having to add each job separately. success: name: Success runs-on: ubuntu-latest - needs: [test, i686, no_std, fmt] + needs: [test, i686, no_std, fmt, doc] # Github branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its # dependencies fails. diff --git a/Cargo.toml b/Cargo.toml index cd1e6d2b..ff41e8a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ serde = ["dep:serde"] [package.metadata.docs.rs] features = ["std", "serde", "rand", "quickcheck", "arbitrary"] +rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "bigint" diff --git a/src/bigint.rs b/src/bigint.rs index 76b64fbb..b4f84b9e 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -24,16 +24,12 @@ mod division; mod multiplication; mod subtraction; +mod arbitrary; mod bits; mod convert; mod power; -mod shift; - -#[cfg(any(feature = "quickcheck", feature = "arbitrary"))] -mod arbitrary; - -#[cfg(feature = "serde")] mod serde; +mod shift; /// A `Sign` is a [`BigInt`]'s composing element. #[derive(PartialEq, PartialOrd, Eq, Ord, Copy, Clone, Debug, Hash)] diff --git a/src/bigint/arbitrary.rs b/src/bigint/arbitrary.rs index 6b809cae..3cb90b30 100644 --- a/src/bigint/arbitrary.rs +++ b/src/bigint/arbitrary.rs @@ -1,3 +1,5 @@ +#![cfg(any(feature = "quickcheck", feature = "arbitrary"))] + use super::{BigInt, Sign}; use crate::BigUint; @@ -5,6 +7,7 @@ use crate::BigUint; use alloc::boxed::Box; #[cfg(feature = "quickcheck")] +#[cfg_attr(docsrs, doc(cfg(feature = "quickcheck")))] impl quickcheck::Arbitrary for BigInt { fn arbitrary(g: &mut quickcheck::Gen) -> Self { let positive = bool::arbitrary(g); @@ -20,6 +23,7 @@ impl quickcheck::Arbitrary for BigInt { } #[cfg(feature = "arbitrary")] +#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))] impl arbitrary::Arbitrary<'_> for BigInt { fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { let positive = bool::arbitrary(u)?; diff --git a/src/bigint/serde.rs b/src/bigint/serde.rs index 5c232f94..6c476920 100644 --- a/src/bigint/serde.rs +++ b/src/bigint/serde.rs @@ -1,3 +1,6 @@ +#![cfg(feature = "serde")] +#![cfg_attr(docsrs, doc(cfg(feature = "serde")))] + use super::{BigInt, Sign}; use serde::de::{Error, Unexpected}; diff --git a/src/bigrand.rs b/src/bigrand.rs index 0b1cb23c..e5cbacdb 100644 --- a/src/bigrand.rs +++ b/src/bigrand.rs @@ -1,4 +1,6 @@ //! Randomization of big integers +#![cfg(feature = "rand")] +#![cfg_attr(docsrs, doc(cfg(feature = "rand")))] use rand::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler}; use rand::prelude::*; diff --git a/src/biguint.rs b/src/biguint.rs index a3bfdcd3..196fa323 100644 --- a/src/biguint.rs +++ b/src/biguint.rs @@ -18,18 +18,14 @@ mod division; mod multiplication; mod subtraction; +mod arbitrary; mod bits; mod convert; mod iter; mod monty; mod power; -mod shift; - -#[cfg(any(feature = "quickcheck", feature = "arbitrary"))] -mod arbitrary; - -#[cfg(feature = "serde")] mod serde; +mod shift; pub(crate) use self::convert::to_str_radix_reversed; pub use self::iter::{U32Digits, U64Digits}; diff --git a/src/biguint/arbitrary.rs b/src/biguint/arbitrary.rs index 76099bc4..9d5c5ccf 100644 --- a/src/biguint/arbitrary.rs +++ b/src/biguint/arbitrary.rs @@ -1,3 +1,5 @@ +#![cfg(any(feature = "quickcheck", feature = "arbitrary"))] + use super::{biguint_from_vec, BigUint}; use crate::big_digit::BigDigit; @@ -6,6 +8,7 @@ use alloc::boxed::Box; use alloc::vec::Vec; #[cfg(feature = "quickcheck")] +#[cfg_attr(docsrs, doc(cfg(feature = "quickcheck")))] impl quickcheck::Arbitrary for BigUint { fn arbitrary(g: &mut quickcheck::Gen) -> Self { // Use arbitrary from Vec @@ -19,6 +22,7 @@ impl quickcheck::Arbitrary for BigUint { } #[cfg(feature = "arbitrary")] +#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))] impl arbitrary::Arbitrary<'_> for BigUint { fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { Ok(biguint_from_vec(Vec::::arbitrary(u)?)) diff --git a/src/biguint/serde.rs b/src/biguint/serde.rs index f0f792be..84bdf505 100644 --- a/src/biguint/serde.rs +++ b/src/biguint/serde.rs @@ -1,3 +1,6 @@ +#![cfg(feature = "serde")] +#![cfg_attr(docsrs, doc(cfg(feature = "serde")))] + use super::{biguint_from_vec, BigUint}; use alloc::vec::Vec; diff --git a/src/lib.rs b/src/lib.rs index e9d2a048..671d544b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,11 +78,24 @@ //! Note that you must use the version of `rand` that `num-bigint` is compatible //! with: `0.8`. //! +//! ### Arbitrary Big Integers +//! +//! `num-bigint` supports `arbitrary` and `quickcheck` features to implement +//! [`arbitrary::Arbitrary`] and [`quickcheck::Arbitrary`], respectively, for both `BigInt` and +//! `BigUint`. These are useful for fuzzing and other forms of randomized testing. +//! +//! ### Serialization +//! +//! The `serde` feature adds implementations of [`Serialize`][serde::Serialize] and +//! [`Deserialize`][serde::Deserialize] for both `BigInt` and `BigUint`. Their serialized data is +//! generated portably, regardless of platform differences like the internal digit size. +//! //! //! ## Compatibility //! //! The `num-bigint` crate is tested for rustc 1.60 and greater. +#![cfg_attr(docsrs, feature(doc_cfg))] #![doc(html_root_url = "https://docs.rs/num-bigint/0.4")] #![warn(rust_2018_idioms)] #![no_std] @@ -99,10 +112,8 @@ use core::fmt; mod macros; mod bigint; -mod biguint; - -#[cfg(feature = "rand")] mod bigrand; +mod biguint; #[cfg(target_pointer_width = "32")] type UsizePromotion = u32; @@ -154,6 +165,7 @@ impl fmt::Display for ParseBigIntError { } #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl std::error::Error for ParseBigIntError { fn description(&self) -> &str { self.__description() @@ -183,6 +195,7 @@ impl TryFromBigIntError { } #[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl std::error::Error for TryFromBigIntError where T: fmt::Debug, @@ -208,6 +221,7 @@ pub use crate::bigint::Sign; pub use crate::bigint::ToBigInt; #[cfg(feature = "rand")] +#[cfg_attr(docsrs, doc(cfg(feature = "rand")))] pub use crate::bigrand::{RandBigInt, RandomBits, UniformBigInt, UniformBigUint}; mod big_digit { From d9fb6e6c3325af0fd3fe41a300f5a25e6fcdbcb6 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 10 May 2024 16:42:30 -0700 Subject: [PATCH 4/8] Mimic the standard library for `adc` and `sbb` fallbacks The intrinsic x86/x86_64 versions are still faster though. --- src/biguint/addition.rs | 12 ++++++------ src/biguint/subtraction.rs | 14 ++++++-------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/biguint/addition.rs b/src/biguint/addition.rs index a054e66d..98b588b6 100644 --- a/src/biguint/addition.rs +++ b/src/biguint/addition.rs @@ -25,14 +25,14 @@ fn adc(carry: u8, a: u32, b: u32, out: &mut u32) -> u8 { } // fallback for environments where we don't have an addcarry intrinsic +// (copied from the standard library's `carrying_add`) #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] #[inline] -fn adc(carry: u8, a: BigDigit, b: BigDigit, out: &mut BigDigit) -> u8 { - use crate::big_digit::DoubleBigDigit; - - let sum = DoubleBigDigit::from(a) + DoubleBigDigit::from(b) + DoubleBigDigit::from(carry); - *out = sum as BigDigit; - (sum >> big_digit::BITS) as u8 +fn adc(carry: u8, lhs: BigDigit, rhs: BigDigit, out: &mut BigDigit) -> u8 { + let (a, b) = lhs.overflowing_add(rhs); + let (c, d) = a.overflowing_add(carry as BigDigit); + *out = c; + u8::from(b || d) } /// Two argument addition of raw slices, `a += b`, returning the carry. diff --git a/src/biguint/subtraction.rs b/src/biguint/subtraction.rs index 58839403..0154a3b0 100644 --- a/src/biguint/subtraction.rs +++ b/src/biguint/subtraction.rs @@ -25,16 +25,14 @@ fn sbb(borrow: u8, a: u32, b: u32, out: &mut u32) -> u8 { } // fallback for environments where we don't have a subborrow intrinsic +// (copied from the standard library's `borrowing_sub`) #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] #[inline] -fn sbb(borrow: u8, a: BigDigit, b: BigDigit, out: &mut BigDigit) -> u8 { - use crate::big_digit::SignedDoubleBigDigit; - - let difference = SignedDoubleBigDigit::from(a) - - SignedDoubleBigDigit::from(b) - - SignedDoubleBigDigit::from(borrow); - *out = difference as BigDigit; - u8::from(difference < 0) +fn sbb(borrow: u8, lhs: BigDigit, rhs: BigDigit, out: &mut BigDigit) -> u8 { + let (a, b) = lhs.overflowing_sub(rhs); + let (c, d) = a.overflowing_sub(borrow as BigDigit); + *out = c; + u8::from(b || d) } pub(super) fn sub2(a: &mut [BigDigit], b: &[BigDigit]) { From 98bea13b5c904ade5a3693cf12f10561978b230f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 10 May 2024 17:18:32 -0700 Subject: [PATCH 5/8] Remove the last use of `SignedDoubleBigDigit` The inverse for `MontyReducer` doesn't need a wider type at all! --- src/biguint/monty.rs | 9 +++++---- src/lib.rs | 6 ------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/biguint/monty.rs b/src/biguint/monty.rs index eeb0791e..a0b26b54 100644 --- a/src/biguint/monty.rs +++ b/src/biguint/monty.rs @@ -3,7 +3,7 @@ use core::mem; use core::ops::Shl; use num_traits::One; -use crate::big_digit::{self, BigDigit, DoubleBigDigit, SignedDoubleBigDigit}; +use crate::big_digit::{self, BigDigit, DoubleBigDigit}; use crate::biguint::BigUint; struct MontyReducer { @@ -15,8 +15,8 @@ struct MontyReducer { fn inv_mod_alt(b: BigDigit) -> BigDigit { assert_ne!(b & 1, 0); - let mut k0 = 2 - b as SignedDoubleBigDigit; - let mut t = (b - 1) as SignedDoubleBigDigit; + let mut k0 = BigDigit::wrapping_sub(2, b); + let mut t = b - 1; let mut i = 1; while i < big_digit::BITS { t = t.wrapping_mul(t); @@ -24,7 +24,8 @@ fn inv_mod_alt(b: BigDigit) -> BigDigit { i <<= 1; } - -k0 as BigDigit + debug_assert_eq!(k0.wrapping_mul(b), 1); + k0.wrapping_neg() } impl MontyReducer { diff --git a/src/lib.rs b/src/lib.rs index 671d544b..6e47479d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,12 +238,6 @@ mod big_digit { pub(crate) type DoubleBigDigit = u128; ); - // A [`SignedDoubleBigDigit`] is the signed version of [`DoubleBigDigit`]. - cfg_digit!( - pub(crate) type SignedDoubleBigDigit = i64; - pub(crate) type SignedDoubleBigDigit = i128; - ); - pub(crate) const BITS: u8 = BigDigit::BITS as u8; pub(crate) const HALF_BITS: u8 = BITS / 2; pub(crate) const HALF: BigDigit = (1 << HALF_BITS) - 1; From 635c6878d772cd8fdea8c4cfc7e06ced1d2bc038 Mon Sep 17 00:00:00 2001 From: yhx-12243 Date: Tue, 28 May 2024 19:02:12 -0400 Subject: [PATCH 6/8] style: use strip_prefix instead of manual starts_with/slice --- src/bigint/convert.rs | 3 +-- src/biguint/convert.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/bigint/convert.rs b/src/bigint/convert.rs index 9c7ab55e..d0e28b67 100644 --- a/src/bigint/convert.rs +++ b/src/bigint/convert.rs @@ -25,8 +25,7 @@ impl Num for BigInt { /// Creates and initializes a [`BigInt`]. #[inline] fn from_str_radix(mut s: &str, radix: u32) -> Result { - let sign = if s.starts_with('-') { - let tail = &s[1..]; + let sign = if let Some(tail) = s.strip_prefix('-') { if !tail.starts_with('+') { s = tail } diff --git a/src/biguint/convert.rs b/src/biguint/convert.rs index a81778c8..3daf3dcb 100644 --- a/src/biguint/convert.rs +++ b/src/biguint/convert.rs @@ -221,8 +221,7 @@ impl Num for BigUint { fn from_str_radix(s: &str, radix: u32) -> Result { assert!(2 <= radix && radix <= 36, "The radix must be within 2...36"); let mut s = s; - if s.starts_with('+') { - let tail = &s[1..]; + if let Some(tail) = s.strip_prefix('+') { if !tail.starts_with('+') { s = tail } From 5d530aa1809f41564e0779df6b1b207797deaa60 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 27 Jun 2024 11:18:20 -0700 Subject: [PATCH 7/8] Fixes for target x32 --- .github/workflows/ci.yaml | 18 +++++++++++++++++- src/biguint/addition.rs | 36 +++++++++++++++++++++++------------- src/biguint/division.rs | 15 ++++++++++++++- src/biguint/subtraction.rs | 36 +++++++++++++++++++++++------------- 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ede5aaed..6ed00986 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -42,6 +42,22 @@ jobs: - run: cargo build - run: ./ci/test_full.sh + # try building the x32 target -- x86_64 with target_pointer_width="32" + # (we can't execute without kernel CONFIG_X86_X32_ABI though) + x32: + name: Test (x32) + runs-on: ubuntu-latest + steps: + - run: | + sudo apt-get update + sudo apt-get install gcc-multilib + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + target: x86_64-unknown-linux-gnux32 + - run: cargo build --target x86_64-unknown-linux-gnux32 --all-features + - run: cargo test --no-run --target x86_64-unknown-linux-gnux32 --all-features + # try a target that doesn't have std at all, but does have alloc no_std: name: No Std @@ -78,7 +94,7 @@ jobs: success: name: Success runs-on: ubuntu-latest - needs: [test, i686, no_std, fmt, doc] + needs: [test, i686, x32, no_std, fmt, doc] # Github branch protection is exceedingly silly and treats "jobs skipped because a dependency # failed" as success. So we have to do some contortions to ensure the job fails if any of its # dependencies fails. diff --git a/src/biguint/addition.rs b/src/biguint/addition.rs index 98b588b6..b6711314 100644 --- a/src/biguint/addition.rs +++ b/src/biguint/addition.rs @@ -7,22 +7,32 @@ use core::iter::Sum; use core::ops::{Add, AddAssign}; use num_traits::CheckedAdd; -// Add with carry: #[cfg(target_arch = "x86_64")] -#[inline] -fn adc(carry: u8, a: u64, b: u64, out: &mut u64) -> u8 { - // Safety: There are absolutely no safety concerns with calling `_addcarry_u64`. - // It's just unsafe for API consistency with other intrinsics. - unsafe { core::arch::x86_64::_addcarry_u64(carry, a, b, out) } -} +use core::arch::x86_64 as arch; #[cfg(target_arch = "x86")] -#[inline] -fn adc(carry: u8, a: u32, b: u32, out: &mut u32) -> u8 { - // Safety: There are absolutely no safety concerns with calling `_addcarry_u32`. - // It's just unsafe for API consistency with other intrinsics. - unsafe { core::arch::x86::_addcarry_u32(carry, a, b, out) } -} +use core::arch::x86 as arch; + +// Add with carry: +#[cfg(target_arch = "x86_64")] +cfg_64!( + #[inline] + fn adc(carry: u8, a: u64, b: u64, out: &mut u64) -> u8 { + // Safety: There are absolutely no safety concerns with calling `_addcarry_u64`. + // It's just unsafe for API consistency with other intrinsics. + unsafe { arch::_addcarry_u64(carry, a, b, out) } + } +); + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +cfg_32!( + #[inline] + fn adc(carry: u8, a: u32, b: u32, out: &mut u32) -> u8 { + // Safety: There are absolutely no safety concerns with calling `_addcarry_u32`. + // It's just unsafe for API consistency with other intrinsics. + unsafe { arch::_addcarry_u32(carry, a, b, out) } + } +); // fallback for environments where we don't have an addcarry intrinsic // (copied from the standard library's `carrying_add`) diff --git a/src/biguint/division.rs b/src/biguint/division.rs index adf9db89..3dfb0bbb 100644 --- a/src/biguint/division.rs +++ b/src/biguint/division.rs @@ -44,8 +44,21 @@ fn div_wide(hi: BigDigit, lo: BigDigit, divisor: BigDigit) -> (BigDigit, BigDigi unsafe { let (div, rem); + cfg_digit!( + macro_rules! div { + () => { + "div {0:e}" + }; + } + macro_rules! div { + () => { + "div {0:r}" + }; + } + ); + core::arch::asm!( - "div {}", + div!(), in(reg) divisor, inout("dx") hi => rem, inout("ax") lo => div, diff --git a/src/biguint/subtraction.rs b/src/biguint/subtraction.rs index 0154a3b0..47a5015f 100644 --- a/src/biguint/subtraction.rs +++ b/src/biguint/subtraction.rs @@ -7,22 +7,32 @@ use core::cmp::Ordering::{Equal, Greater, Less}; use core::ops::{Sub, SubAssign}; use num_traits::CheckedSub; -// Subtract with borrow: #[cfg(target_arch = "x86_64")] -#[inline] -fn sbb(borrow: u8, a: u64, b: u64, out: &mut u64) -> u8 { - // Safety: There are absolutely no safety concerns with calling `_subborrow_u64`. - // It's just unsafe for API consistency with other intrinsics. - unsafe { core::arch::x86_64::_subborrow_u64(borrow, a, b, out) } -} +use core::arch::x86_64 as arch; #[cfg(target_arch = "x86")] -#[inline] -fn sbb(borrow: u8, a: u32, b: u32, out: &mut u32) -> u8 { - // Safety: There are absolutely no safety concerns with calling `_subborrow_u32`. - // It's just unsafe for API consistency with other intrinsics. - unsafe { core::arch::x86::_subborrow_u32(borrow, a, b, out) } -} +use core::arch::x86 as arch; + +// Subtract with borrow: +#[cfg(target_arch = "x86_64")] +cfg_64!( + #[inline] + fn sbb(borrow: u8, a: u64, b: u64, out: &mut u64) -> u8 { + // Safety: There are absolutely no safety concerns with calling `_subborrow_u64`. + // It's just unsafe for API consistency with other intrinsics. + unsafe { arch::_subborrow_u64(borrow, a, b, out) } + } +); + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +cfg_32!( + #[inline] + fn sbb(borrow: u8, a: u32, b: u32, out: &mut u32) -> u8 { + // Safety: There are absolutely no safety concerns with calling `_subborrow_u32`. + // It's just unsafe for API consistency with other intrinsics. + unsafe { arch::_subborrow_u32(borrow, a, b, out) } + } +); // fallback for environments where we don't have a subborrow intrinsic // (copied from the standard library's `borrowing_sub`) From 2b33deba7cc014f09275f6a0f9b575c67382afdf Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 27 Jun 2024 11:38:24 -0700 Subject: [PATCH 8/8] Release 0.4.6 --- Cargo.toml | 2 +- RELEASES.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ff41e8a9..720512a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = [ "algorithms", "data-structures", "science" ] license = "MIT OR Apache-2.0" name = "num-bigint" repository = "https://github.com/rust-num/num-bigint" -version = "0.4.5" +version = "0.4.6" readme = "README.md" exclude = ["/ci/*", "/.github/*"] edition = "2021" diff --git a/RELEASES.md b/RELEASES.md index f3163116..bc4c3534 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,11 @@ +# Release 0.4.6 (2024-06-27) + +- [Fixed compilation on `x86_64-unknown-linux-gnux32`.][312] + +**Contributors**: @cuviper, @ralphtandetzky, @yhx-12243 + +[312]: https://github.com/rust-num/num-bigint/pull/312 + # Release 0.4.5 (2024-05-06) - [Upgrade to 2021 edition, **MSRV 1.60**][292]