Skip to content

Commit

Permalink
Use the alloc crate for no_std (Rust 1.36+)
Browse files Browse the repository at this point in the history
  • Loading branch information
cuviper committed Jan 13, 2020
1 parent dec114d commit c76d0d3
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 80 deletions.
9 changes: 9 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ rust:
- 1.22.0 # rand
- 1.26.0 # has_i128
- 1.31.0 # 2018!
- 1.36.0 # alloc
- stable
- beta
- nightly
Expand All @@ -19,6 +20,14 @@ matrix:
apt:
packages:
- gcc-multilib
# try a target that doesn't have std at all, but does have alloc
- name: "no_std"
rust: stable
env: TARGET=thumbv6m-none-eabi
before_script:
- rustup target add $TARGET
script:
- cargo build --verbose --target $TARGET --no-default-features --features i128
- name: "rustfmt"
rust: 1.31.0
before_script:
Expand Down
2 changes: 1 addition & 1 deletion ci/rustup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
set -ex

export TRAVIS_RUST_VERSION
for TRAVIS_RUST_VERSION in 1.15.0 1.22.0 1.26.0 stable beta nightly; do
for TRAVIS_RUST_VERSION in 1.15.0 1.22.0 1.26.0 1.31.0 1.36.0 stable beta nightly; do
run="rustup run $TRAVIS_RUST_VERSION"
$run cargo build --verbose
$run $PWD/ci/test_full.sh
Expand Down
43 changes: 30 additions & 13 deletions ci/test_full.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ set -ex

echo Testing num-bigint on rustc ${TRAVIS_RUST_VERSION}

FEATURES="serde"
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable.*|1.31.0|1.26.0|1.22.0)$ ]]; then
FEATURES="$FEATURES rand"
fi
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable.*|1.31.0|1.26.0)$ ]]; then
FEATURES="$FEATURES i128"
fi
if [[ "$TRAVIS_RUST_VERSION" =~ ^(nightly|beta|stable.*|1.31.0)$ ]]; then
FEATURES="$FEATURES quickcheck quickcheck_macros"
fi
case "$TRAVIS_RUST_VERSION" in
1.1[5-9].* | 1.2[0-1].*) STD_FEATURES="serde" ;;
1.2[2-5].*) STD_FEATURES="serde rand" ;;
1.2[6-9].* | 1.30.*) STD_FEATURES="serde rand i128" ;;
*) STD_FEATURES="serde rand i128 quickcheck quickcheck_macros" ;;
esac

case "$TRAVIS_RUST_VERSION" in
1.1[5-9].* | 1.2[0-9].* | 1.3[0-5].*) ;;
*) NO_STD_FEATURES="i128" ;;
esac

# num-bigint should build and test everywhere.
cargo build --verbose
Expand All @@ -24,14 +25,30 @@ cargo build --no-default-features --features="std"
cargo test --no-default-features --features="std"

# Each isolated feature should also work everywhere.
for feature in $FEATURES; do
for feature in $STD_FEATURES; do
cargo build --verbose --no-default-features --features="std $feature"
cargo test --verbose --no-default-features --features="std $feature"
done

# test all supported features together
cargo build --features="std $FEATURES"
cargo test --features="std $FEATURES"
cargo build --features="std $STD_FEATURES"
cargo test --features="std $STD_FEATURES"

if test -n "${NO_STD_FEATURES:+true}"; then
# It should build with minimal features too.
cargo build --no-default-features
cargo test --no-default-features

# Each isolated feature should also work everywhere.
for feature in $NO_STD_FEATURES; do
cargo build --verbose --no-default-features --features="$feature"
cargo test --verbose --no-default-features --features="$feature"
done

# test all supported features together
cargo build --no-default-features --features="$NO_STD_FEATURES"
cargo test --no-default-features --features="$NO_STD_FEATURES"
fi

# make sure benchmarks can be built
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
Expand Down
10 changes: 5 additions & 5 deletions src/algorithms.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::borrow::Cow;
use std::cmp;
use std::cmp::Ordering::{self, Equal, Greater, Less};
use std::iter::repeat;
use std::mem;
use core::cmp;
use core::cmp::Ordering::{self, Equal, Greater, Less};
use core::iter::repeat;
use core::mem;
use std_alloc::{Cow, Vec};
use traits;
use traits::{One, Zero};

Expand Down
26 changes: 15 additions & 11 deletions src/bigint.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
use std::cmp::Ordering::{self, Equal, Greater, Less};
use std::default::Default;
use std::fmt;
use std::iter::{Product, Sum};
use std::mem;
use std::ops::{
use core::cmp::Ordering::{self, Equal, Greater, Less};
use core::default::Default;
use core::fmt;
use core::iter::{Product, Sum};
use core::mem;
use core::ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
};
use std::str::{self, FromStr};
use core::str::{self, FromStr};
#[cfg(has_i128)]
use std::{i128, u128};
use std::{i64, u64};
use core::{i128, u128};
use core::{i64, u64};
#[cfg(feature = "std")]
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
#[cfg(feature = "quickcheck")]
use std_alloc::Box;
use std_alloc::{String, Vec};

#[cfg(feature = "serde")]
use serde;
Expand Down
2 changes: 1 addition & 1 deletion src/bigrand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<R: Rng + ?Sized> RandBigInt for R {

#[cfg(u64_digit)]
fn gen_biguint(&mut self, bit_size: usize) -> BigUint {
use std::slice;
use core::slice;

let (digits, rem) = bit_size.div_rem(&32);
let native_digits = bit_size.div_ceil(&64);
Expand Down
67 changes: 47 additions & 20 deletions src/biguint.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::cmp;
use std::cmp::Ordering::{self, Equal, Greater, Less};
use std::default::Default;
use std::fmt;
use std::iter::{Product, Sum};
use std::mem;
use std::ops::{
use core::cmp;
use core::cmp::Ordering::{self, Equal, Greater, Less};
use core::default::Default;
use core::fmt;
use core::iter::{Product, Sum};
use core::mem;
use core::ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
Mul, MulAssign, Neg, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
};
use std::str::{self, FromStr};
use std::{f32, f64};
use std::{u32, u64, u8};
use core::str::{self, FromStr};
use core::{f32, f64};
use core::{u32, u64, u8};
#[cfg(feature = "std")]
#[allow(deprecated, unused_imports)]
use std::ascii::AsciiExt;
#[cfg(feature = "quickcheck")]
use std_alloc::Box;
use std_alloc::{Cow, String, Vec};

#[cfg(feature = "serde")]
use serde;

use integer::{Integer, Roots};
use traits::float::FloatCore;
use traits::{
CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Float, FromPrimitive, Num, One, Pow,
ToPrimitive, Unsigned, Zero,
CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, FromPrimitive, Num, One, Pow, ToPrimitive,
Unsigned, Zero,
};

use big_digit::{self, BigDigit};
Expand Down Expand Up @@ -215,10 +219,15 @@ fn from_radix_digits_be(v: &[u8], radix: u32) -> BigUint {
debug_assert!(!v.is_empty() && !radix.is_power_of_two());
debug_assert!(v.iter().all(|&c| u32::from(c) < radix));

#[cfg(feature = "std")]
let radix_log2 = f64::from(radix).log2();
#[cfg(not(feature = "std"))]
let radix_log2 = ilog2(radix.next_power_of_two()) as f64;

// Estimate how big the result will be, so we can pre-allocate it.
let bits = f64::from(radix).log2() * v.len() as f64;
let bits = radix_log2 * v.len() as f64;
let big_digits = (bits / big_digit::BITS as f64).ceil();
let mut data = Vec::with_capacity(big_digits as usize);
let mut data = Vec::with_capacity(big_digits.to_usize().unwrap_or(0));

let (base, power) = get_radix_base(radix, big_digit::BITS);
let radix = radix as BigDigit;
Expand Down Expand Up @@ -1586,6 +1595,7 @@ impl Roots for BigUint {

let max_bits = bits / n as usize + 1;

#[cfg(feature = "std")]
let guess = if let Some(f) = self.to_f64() {
// We fit in `f64` (lossy), so get a better initial guess from that.
BigUint::from_f64((f.ln() / f64::from(n)).exp()).unwrap()
Expand All @@ -1603,6 +1613,9 @@ impl Roots for BigUint {
}
};

#[cfg(not(feature = "std"))]
let guess = BigUint::one() << max_bits;

let n_min_1 = n - 1;
fixpoint(guess, max_bits, move |s| {
let q = self / s.pow(n_min_1);
Expand All @@ -1626,6 +1639,7 @@ impl Roots for BigUint {
let bits = self.bits();
let max_bits = bits / 2 as usize + 1;

#[cfg(feature = "std")]
let guess = if let Some(f) = self.to_f64() {
// We fit in `f64` (lossy), so get a better initial guess from that.
BigUint::from_f64(f.sqrt()).unwrap()
Expand All @@ -1638,6 +1652,9 @@ impl Roots for BigUint {
(self >> scale).sqrt() << root_scale
};

#[cfg(not(feature = "std"))]
let guess = BigUint::one() << max_bits;

fixpoint(guess, max_bits, move |s| {
let q = self / s;
let t = s + q;
Expand All @@ -1658,6 +1675,7 @@ impl Roots for BigUint {
let bits = self.bits();
let max_bits = bits / 3 as usize + 1;

#[cfg(feature = "std")]
let guess = if let Some(f) = self.to_f64() {
// We fit in `f64` (lossy), so get a better initial guess from that.
BigUint::from_f64(f.cbrt()).unwrap()
Expand All @@ -1670,6 +1688,9 @@ impl Roots for BigUint {
(self >> scale).cbrt() << root_scale
};

#[cfg(not(feature = "std"))]
let guess = BigUint::one() << max_bits;

fixpoint(guess, max_bits, move |s| {
let q = self / (s * s);
let t = (s << 1) + q;
Expand Down Expand Up @@ -1836,7 +1857,7 @@ impl FromPrimitive for BigUint {
return Some(BigUint::zero());
}

let (mantissa, exponent, sign) = Float::integer_decode(n);
let (mantissa, exponent, sign) = FloatCore::integer_decode(n);

if sign == -1 {
return None;
Expand Down Expand Up @@ -2011,9 +2032,15 @@ fn to_inexact_bitwise_digits_le(u: &BigUint, bits: usize) -> Vec<u8> {
fn to_radix_digits_le(u: &BigUint, radix: u32) -> Vec<u8> {
debug_assert!(!u.is_zero() && !radix.is_power_of_two());

#[cfg(feature = "std")]
let radix_log2 = f64::from(radix).log2();
#[cfg(not(feature = "std"))]
let radix_log2 = ilog2(radix) as f64;

// Estimate how big the result will be, so we can pre-allocate it.
let radix_digits = ((u.bits() as f64) / f64::from(radix).log2()).ceil();
let mut res = Vec::with_capacity(radix_digits as usize);
let radix_digits = ((u.bits() as f64) / radix_log2).ceil();
let mut res = Vec::with_capacity(radix_digits.to_usize().unwrap_or(0));

let mut digits = u.clone();

let (base, power) = get_radix_base(radix, big_digit::HALF_BITS);
Expand Down
32 changes: 28 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,31 @@
//! The `num-bigint` crate is tested for rustc 1.15 and greater.

#![doc(html_root_url = "https://docs.rs/num-bigint/0.2")]
// We don't actually support `no_std` yet, and probably won't until `alloc` is stable. We're just
// reserving this ability with the "std" feature now, and compilation will fail without.
#![cfg_attr(not(feature = "std"), no_std)]
#![no_std]

#[cfg(feature = "std")]
#[macro_use]
extern crate std;

#[cfg(feature = "std")]
mod std_alloc {
pub use std::borrow::Cow;
pub use std::boxed::Box;
pub use std::string::String;
pub use std::vec::Vec;
}

#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;

#[cfg(not(feature = "std"))]
mod std_alloc {
pub use alloc::borrow::Cow;
pub use alloc::boxed::Box;
pub use alloc::string::String;
pub use alloc::vec::Vec;
}

#[cfg(feature = "rand")]
extern crate rand;
Expand All @@ -117,8 +139,9 @@ extern crate num_traits as traits;
#[cfg(feature = "quickcheck")]
extern crate quickcheck;

use core::fmt;
#[cfg(feature = "std")]
use std::error::Error;
use std::fmt;

#[macro_use]
mod macros;
Expand Down Expand Up @@ -178,6 +201,7 @@ impl fmt::Display for ParseBigIntError {
}
}

#[cfg(feature = "std")]
impl Error for ParseBigIntError {
fn description(&self) -> &str {
self.__description()
Expand Down
5 changes: 3 additions & 2 deletions src/monty.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::mem;
use std::ops::Shl;
use core::mem;
use core::ops::Shl;
use std_alloc::Vec;
use traits::{One, Zero};

use big_digit::{self, BigDigit, DoubleBigDigit, SignedDoubleBigDigit};
Expand Down
Loading

0 comments on commit c76d0d3

Please sign in to comment.