diff --git a/Cargo.toml b/Cargo.toml index 851b1ca2128..e81de35779c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,15 @@ Random number generators and other randomness functionality. keywords = ["random", "rng"] [dependencies] -libc = "0.2" +libc = { version = "0.2", optional = true } +core_io = { version = "0.1", optional = true } # enable use of read module on not(std) + +[features] +default = ["std"] +std = ["libc"] +box = [] # enable use of Box on not(std), requires alloc crate and feature +vec = [] # enable use of Vec on not(std), requires collections crate and feature +rdrand = [] # with not(std), requires core_io [dev-dependencies] log = "0.3.0" diff --git a/src/chacha.rs b/src/chacha.rs index a347ec51f2c..f3870f5ebeb 100644 --- a/src/chacha.rs +++ b/src/chacha.rs @@ -10,7 +10,7 @@ //! The ChaCha random number generator. -use std::num::Wrapping as w; +use core::num::Wrapping as w; use {Rng, SeedableRng, Rand, w32}; const KEY_WORDS : usize = 8; // 8 words for the 256-bit key diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 50f9d955bbc..c70a24c6e41 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -17,19 +17,19 @@ //! internally. The `IndependentSample` trait is for generating values //! that do not need to record state. -use std::marker; +use core::marker; use {Rng, Rand}; pub use self::range::Range; -pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT}; -pub use self::normal::{Normal, LogNormal}; -pub use self::exponential::Exp; +#[cfg(feature="std")] pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT}; +#[cfg(feature="std")] pub use self::normal::{Normal, LogNormal}; +#[cfg(feature="std")] pub use self::exponential::Exp; pub mod range; -pub mod gamma; -pub mod normal; -pub mod exponential; +#[cfg(feature="std")] pub mod gamma; +#[cfg(feature="std")] pub mod normal; +#[cfg(feature="std")] pub mod exponential; /// Types that can be used to create a random instance of `Support`. pub trait Sample { @@ -201,7 +201,7 @@ impl<'a, T: Clone> IndependentSample for WeightedChoice<'a, T> { } } -mod ziggurat_tables; +#[cfg(feature="std")] mod ziggurat_tables; /// Sample a random number using the Ziggurat method (specifically the /// ZIGNOR variant from Doornik 2005). Most of the arguments are @@ -218,6 +218,7 @@ mod ziggurat_tables; // the perf improvement (25-50%) is definitely worth the extra code // size from force-inlining. +#[cfg(feature="std")] #[inline(always)] fn ziggurat( rng: &mut R, diff --git a/src/distributions/range.rs b/src/distributions/range.rs index 3cf47be0207..945c3dd1bda 100644 --- a/src/distributions/range.rs +++ b/src/distributions/range.rs @@ -12,7 +12,7 @@ // this is surprisingly complicated to be both generic & correct -use std::num::Wrapping as w; +use core::num::Wrapping as w; use Rng; use distributions::{Sample, IndependentSample}; @@ -98,7 +98,7 @@ macro_rules! integer_impl { fn construct_range(low: $ty, high: $ty) -> Range<$ty> { let range = (w(high as $unsigned) - w(low as $unsigned)).0; - let unsigned_max: $unsigned = ::std::$unsigned::MAX; + let unsigned_max: $unsigned = ::core::$unsigned::MAX; // this is the largest number that fits into $unsigned // that `range` divides evenly, so, if we've sampled @@ -185,7 +185,7 @@ mod tests { $( let v: &[($ty, $ty)] = &[(0, 10), (10, 127), - (::std::$ty::MIN, ::std::$ty::MAX)]; + (::core::$ty::MIN, ::core::$ty::MAX)]; for &(low, high) in v.iter() { let mut sampler: Range<$ty> = Range::new(low, high); for _ in 0..1000 { diff --git a/src/isaac.rs b/src/isaac.rs index 42de3523fb0..ea8f6c1137b 100644 --- a/src/isaac.rs +++ b/src/isaac.rs @@ -12,9 +12,9 @@ #![allow(non_camel_case_types)] -use std::slice; -use std::iter::repeat; -use std::num::Wrapping as w; +use core::slice; +use core::iter::repeat; +use core::num::Wrapping as w; use {Rng, SeedableRng, Rand, w32, w64}; diff --git a/src/lib.rs b/src/lib.rs index 472e4ece331..3e3d7b4e014 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -241,16 +241,31 @@ html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/rand/")] +#![cfg_attr(not(feature="std"),no_std)] +#![cfg_attr(all(feature="box",not(feature="std")),feature(alloc))] +#![cfg_attr(all(feature="vec",not(feature="std")),feature(collections))] +#![cfg_attr(feature="rdrand",feature(asm))] + #[cfg(test)] #[macro_use] extern crate log; -use std::cell::RefCell; -use std::marker; -use std::mem; -use std::io; -use std::rc::Rc; -use std::num::Wrapping as w; +#[cfg(feature="std")] extern crate std as core; +#[cfg(all(feature="core_io",not(feature="std")))] extern crate core_io as io; +#[cfg(all(feature="box",not(feature="std")))] extern crate alloc; +#[cfg(all(feature="vec",not(feature="std")))] extern crate collections; + +#[cfg(all(not(feature="std"),feature="rdrand",not(feature="core_io")))] +use using::rdrand::feature::without::std::feature::requires::core_io::feature; -pub use os::OsRng; +#[cfg(all(feature="std",not(feature="rdrand")))] use core::cell::RefCell; +use core::marker; +use core::mem; +#[cfg(feature="std")] use std::io; +#[cfg(all(feature="std",not(feature="rdrand")))] use std::rc::Rc; +use core::num::Wrapping as w; +#[cfg(all(feature="box",not(feature="std")))] use alloc::boxed::Box; +#[cfg(all(feature="vec",not(feature="std")))] use collections::vec::Vec; + +#[cfg(any(feature="std",feature="rdrand"))] pub use os::OsRng; pub use isaac::{IsaacRng, Isaac64Rng}; pub use chacha::ChaChaRng; @@ -268,8 +283,8 @@ pub mod isaac; pub mod chacha; pub mod reseeding; mod rand_impls; -pub mod os; -pub mod read; +#[cfg(any(feature="std",feature="rdrand"))] pub mod os; +#[cfg(any(feature="std",feature="core_io"))] pub mod read; #[allow(bad_style)] type w64 = w; @@ -576,6 +591,7 @@ impl<'a, R: ?Sized> Rng for &'a mut R where R: Rng { } } +#[cfg(any(feature="box",feature="std"))] impl Rng for Box where R: Rng { fn next_u32(&mut self) -> u32 { (**self).next_u32() @@ -810,6 +826,7 @@ impl StdRng { /// /// Reading the randomness from the OS may fail, and any error is /// propagated via the `io::Result` return value. + #[cfg(any(feature="std",feature="rdrand"))] pub fn new() -> io::Result { OsRng::new().map(|mut r| StdRng { rng: r.gen() }) } @@ -848,6 +865,7 @@ impl<'a> SeedableRng<&'a [usize]> for StdRng { /// /// This will read randomness from the operating system to seed the /// generator. +#[cfg(any(feature="std",feature="rdrand"))] pub fn weak_rng() -> XorShiftRng { match OsRng::new() { Ok(mut r) => r.gen(), @@ -856,8 +874,10 @@ pub fn weak_rng() -> XorShiftRng { } /// Controls how the thread-local RNG is reseeded. +#[cfg(all(feature="std",not(feature="rdrand")))] struct ThreadRngReseeder; +#[cfg(all(feature="std",not(feature="rdrand")))] impl reseeding::Reseeder for ThreadRngReseeder { fn reseed(&mut self, rng: &mut StdRng) { *rng = match StdRng::new() { @@ -866,10 +886,13 @@ impl reseeding::Reseeder for ThreadRngReseeder { } } } +#[cfg(all(feature="std",not(feature="rdrand")))] const THREAD_RNG_RESEED_THRESHOLD: u64 = 32_768; +#[cfg(all(feature="std",not(feature="rdrand")))] type ThreadRngInner = reseeding::ReseedingRng; /// The thread-local RNG. +#[cfg(all(feature="std",not(feature="rdrand")))] #[derive(Clone)] pub struct ThreadRng { rng: Rc>, @@ -886,6 +909,7 @@ pub struct ThreadRng { /// if the operating system random number generator is rigged to give /// the same sequence always. If absolute consistency is required, /// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. +#[cfg(all(feature="std",not(feature="rdrand")))] pub fn thread_rng() -> ThreadRng { // used to make space in TLS for a random number generator thread_local!(static THREAD_RNG_KEY: Rc> = { @@ -902,6 +926,7 @@ pub fn thread_rng() -> ThreadRng { ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } } +#[cfg(all(feature="std",not(feature="rdrand")))] impl Rng for ThreadRng { fn next_u32(&mut self) -> u32 { self.rng.borrow_mut().next_u32() @@ -917,6 +942,14 @@ impl Rng for ThreadRng { } } +#[cfg(feature="rdrand")] +pub use os::OsRng as ThreadRng; + +#[cfg(feature="rdrand")] +pub fn thread_rng() -> ThreadRng { + OsRng::new().unwrap() +} + /// Generates a random value using the thread-local random number generator. /// /// `random()` can generate various types of random things, and so may require @@ -959,6 +992,7 @@ impl Rng for ThreadRng { /// *x = rng.gen(); /// } /// ``` +#[cfg(any(feature="std",feature="rdrand"))] #[inline] pub fn random() -> T { thread_rng().gen() @@ -975,6 +1009,7 @@ pub fn random() -> T { /// let sample = sample(&mut rng, 1..100, 5); /// println!("{:?}", sample); /// ``` +#[cfg(any(feature="vec",feature="std"))] pub fn sample(rng: &mut R, iterable: I, amount: usize) -> Vec where I: IntoIterator, R: Rng, diff --git a/src/os.rs b/src/os.rs index fc36012b827..ec19b3661d9 100644 --- a/src/os.rs +++ b/src/os.rs @@ -11,7 +11,8 @@ //! Interfaces to the operating system provided random number //! generators. -use std::io; +#[cfg(not(feature="std"))] use io; +#[cfg(feature="std")] use std::io; use Rng; /// A random number generator that retrieves randomness straight from @@ -41,7 +42,7 @@ impl Rng for OsRng { } #[cfg(all(unix, not(target_os = "ios"), - not(target_os = "nacl")))] + not(target_os = "nacl"), not(feature = "rdrand")))] mod imp { extern crate libc; @@ -198,7 +199,7 @@ mod imp { } } -#[cfg(target_os = "ios")] +#[cfg(all(target_os = "ios", not(feature = "rdrand")))] mod imp { extern crate libc; @@ -248,7 +249,7 @@ mod imp { } } -#[cfg(windows)] +#[cfg(all(windows, not(feature = "rdrand")))] mod imp { use std::io; use std::mem; @@ -339,7 +340,7 @@ mod imp { } } -#[cfg(target_os = "nacl")] +#[cfg(all(target_os = "nacl", not(feature = "rdrand")))] mod imp { extern crate libc; @@ -417,6 +418,54 @@ mod imp { } +#[cfg(feature = "rdrand")] +mod imp { + #[cfg(not(feature="std"))] use io; + #[cfg(feature="std")] use std::io; + + use Rng; + + pub struct OsRng; + + impl OsRng { + pub fn new() -> io::Result { + Ok(OsRng) + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + let ret; + let mut retry=10; + unsafe{asm!(" +1: + rdrand $0 + jc 2f + dec $1 + jnz 1b +2: + ":"=r"(ret),"=r"(retry):"1"(retry)::"volatile")}; + if retry==0 { panic!("RDRAND failure") } + ret + } + #[cfg(target_arch="x86_64")] + fn next_u64(&mut self) -> u64 { + let ret; + let mut retry=10; + unsafe{asm!(" +1: + rdrand $0 + jc 2f + dec $1 + jnz 1b +2: + ":"=r"(ret),"=r"(retry):"1"(retry)::"volatile")}; + if retry==0 { panic!("RDRAND failure") } + ret + } + } +} + #[cfg(test)] mod test { use std::sync::mpsc::channel; diff --git a/src/rand_impls.rs b/src/rand_impls.rs index 5a7e3de0b03..0d501a62f11 100644 --- a/src/rand_impls.rs +++ b/src/rand_impls.rs @@ -10,8 +10,8 @@ //! The implementations of `Rand` for the built-in types. -use std::char; -use std::mem; +use core::char; +use core::mem; use {Rand,Rng}; diff --git a/src/read.rs b/src/read.rs index 9e420bcde4e..ad78fab6fe7 100644 --- a/src/read.rs +++ b/src/read.rs @@ -10,8 +10,9 @@ //! A wrapper around any Read to treat it as an RNG. -use std::io::{self, Read}; -use std::mem; +#[cfg(not(feature="std"))] use io::{self, Read}; +#[cfg(feature="std")] use std::io::{self, Read}; +use core::mem; use Rng; /// An RNG that reads random bytes straight from a `Read`. This will diff --git a/src/reseeding.rs b/src/reseeding.rs index 39e464d7f8b..6585516fcdb 100644 --- a/src/reseeding.rs +++ b/src/reseeding.rs @@ -11,7 +11,7 @@ //! A wrapper around another RNG that reseeds it after it //! generates a certain number of random bytes. -use std::default::Default; +use core::default::Default; use {Rng, SeedableRng};