Replace SeedableRng impl for SmallRng with inherent fns (#1368)
* Simplify redundant doc-link * Remove impl of SeedableRng for SmallRng * Fix SeedableRng::Seed type for StdRng * SmallRng: do not expect thread_rng * Make SmallRng::from_thread_rng infallible * Fix benchmarks (SmallRng does not have from_entropy)
This commit is contained in:
@@ -50,7 +50,7 @@ gen_bytes!(gen_bytes_chacha12, ChaCha12Rng::from_entropy());
|
||||
gen_bytes!(gen_bytes_chacha20, ChaCha20Rng::from_entropy());
|
||||
gen_bytes!(gen_bytes_std, StdRng::from_entropy());
|
||||
#[cfg(feature = "small_rng")]
|
||||
gen_bytes!(gen_bytes_small, SmallRng::from_entropy());
|
||||
gen_bytes!(gen_bytes_small, SmallRng::from_thread_rng());
|
||||
gen_bytes!(gen_bytes_os, OsRng);
|
||||
|
||||
macro_rules! gen_uint {
|
||||
@@ -80,7 +80,7 @@ gen_uint!(gen_u32_chacha12, u32, ChaCha12Rng::from_entropy());
|
||||
gen_uint!(gen_u32_chacha20, u32, ChaCha20Rng::from_entropy());
|
||||
gen_uint!(gen_u32_std, u32, StdRng::from_entropy());
|
||||
#[cfg(feature = "small_rng")]
|
||||
gen_uint!(gen_u32_small, u32, SmallRng::from_entropy());
|
||||
gen_uint!(gen_u32_small, u32, SmallRng::from_thread_rng());
|
||||
gen_uint!(gen_u32_os, u32, OsRng);
|
||||
|
||||
gen_uint!(gen_u64_step, u64, StepRng::new(0, 1));
|
||||
@@ -93,7 +93,7 @@ gen_uint!(gen_u64_chacha12, u64, ChaCha12Rng::from_entropy());
|
||||
gen_uint!(gen_u64_chacha20, u64, ChaCha20Rng::from_entropy());
|
||||
gen_uint!(gen_u64_std, u64, StdRng::from_entropy());
|
||||
#[cfg(feature = "small_rng")]
|
||||
gen_uint!(gen_u64_small, u64, SmallRng::from_entropy());
|
||||
gen_uint!(gen_u64_small, u64, SmallRng::from_thread_rng());
|
||||
gen_uint!(gen_u64_os, u64, OsRng);
|
||||
|
||||
macro_rules! init_gen {
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ const N_RESAMPLES: usize = 10_000;
|
||||
macro_rules! sample {
|
||||
($R:ty, $T:ty, $U:ty, $g:expr) => {
|
||||
$g.bench_function(BenchmarkId::new(stringify!($R), "single"), |b| {
|
||||
let mut rng = <$R>::from_entropy();
|
||||
let mut rng = <$R>::from_rng(thread_rng()).unwrap();
|
||||
let x = rng.gen::<$U>();
|
||||
let bits = (<$T>::BITS / 2);
|
||||
let mask = (1 as $U).wrapping_neg() >> bits;
|
||||
@@ -35,7 +35,7 @@ macro_rules! sample {
|
||||
});
|
||||
|
||||
$g.bench_function(BenchmarkId::new(stringify!($R), "distr"), |b| {
|
||||
let mut rng = <$R>::from_entropy();
|
||||
let mut rng = <$R>::from_rng(thread_rng()).unwrap();
|
||||
let x = rng.gen::<$U>();
|
||||
let bits = (<$T>::BITS / 2);
|
||||
let mask = (1 as $U).wrapping_neg() >> bits;
|
||||
|
||||
@@ -27,7 +27,7 @@ const N_RESAMPLES: usize = 10_000;
|
||||
macro_rules! single_random {
|
||||
($R:ty, $T:ty, $g:expr) => {
|
||||
$g.bench_function(BenchmarkId::new(stringify!($T), stringify!($R)), |b| {
|
||||
let mut rng = <$R>::from_entropy();
|
||||
let mut rng = <$R>::from_rng(thread_rng()).unwrap();
|
||||
let (mut low, mut high);
|
||||
loop {
|
||||
low = <$T>::from_bits(rng.gen());
|
||||
@@ -63,7 +63,7 @@ fn single_random(c: &mut Criterion) {
|
||||
macro_rules! distr_random {
|
||||
($R:ty, $T:ty, $g:expr) => {
|
||||
$g.bench_function(BenchmarkId::new(stringify!($T), stringify!($R)), |b| {
|
||||
let mut rng = <$R>::from_entropy();
|
||||
let mut rng = <$R>::from_rng(thread_rng()).unwrap();
|
||||
let dist = loop {
|
||||
let low = <$T>::from_bits(rng.gen());
|
||||
let high = <$T>::from_bits(rng.gen());
|
||||
|
||||
@@ -80,7 +80,7 @@ pub trait BlockRngCore {
|
||||
/// A marker trait used to indicate that an [`RngCore`] implementation is
|
||||
/// supposed to be cryptographically secure.
|
||||
///
|
||||
/// See [`CryptoRng`][crate::CryptoRng] docs for more information.
|
||||
/// See [`CryptoRng`] docs for more information.
|
||||
pub trait CryptoBlockRng: BlockRngCore { }
|
||||
|
||||
/// A wrapper type implementing [`RngCore`] for some type implementing
|
||||
|
||||
+47
-53
@@ -22,18 +22,12 @@ type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus;
|
||||
/// Note that depending on the application, [`StdRng`] may be faster on many
|
||||
/// modern platforms while providing higher-quality randomness. Furthermore,
|
||||
/// `SmallRng` is **not** a good choice when:
|
||||
/// - Security against prediction is important. Use [`StdRng`] instead.
|
||||
/// - Seeds with many zeros are provided. In such cases, it takes `SmallRng`
|
||||
/// about 10 samples to produce 0 and 1 bits with equal probability. Either
|
||||
/// provide seeds with an approximately equal number of 0 and 1 (for example
|
||||
/// by using [`SeedableRng::from_entropy`] or [`SeedableRng::seed_from_u64`]),
|
||||
/// or use [`StdRng`] instead.
|
||||
///
|
||||
/// The algorithm is deterministic but should not be considered reproducible
|
||||
/// due to dependence on platform and possible replacement in future
|
||||
/// library versions. For a reproducible generator, use a named PRNG from an
|
||||
/// external crate, e.g. [rand_xoshiro] or [rand_chacha].
|
||||
/// Refer also to [The Book](https://rust-random.github.io/book/guide-rngs.html).
|
||||
/// - Portability is required. Its implementation is not fixed. Use a named
|
||||
/// generator from an external crate instead, for example [rand_xoshiro] or
|
||||
/// [rand_chacha]. Refer also to
|
||||
/// [The Book](https://rust-random.github.io/book/guide-rngs.html).
|
||||
/// - Security against prediction is important. Use [`StdRng`] instead.
|
||||
///
|
||||
/// The PRNG algorithm in `SmallRng` is chosen to be efficient on the current
|
||||
/// platform, without consideration for cryptography or security. The size of
|
||||
@@ -41,39 +35,7 @@ type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus;
|
||||
/// `Xoshiro256PlusPlus` on 64-bit platforms and `Xoshiro128PlusPlus` on 32-bit
|
||||
/// platforms. Both are also implemented by the [rand_xoshiro] crate.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Initializing `SmallRng` with a random seed can be done using [`SeedableRng::from_entropy`]:
|
||||
///
|
||||
/// ```
|
||||
/// use rand::{Rng, SeedableRng};
|
||||
/// use rand::rngs::SmallRng;
|
||||
///
|
||||
/// // Create small, cheap to initialize and fast RNG with a random seed.
|
||||
/// // The randomness is supplied by the operating system.
|
||||
/// let mut small_rng = SmallRng::from_entropy();
|
||||
/// # let v: u32 = small_rng.gen();
|
||||
/// ```
|
||||
///
|
||||
/// When initializing a lot of `SmallRng`'s, using [`thread_rng`] can be more
|
||||
/// efficient:
|
||||
///
|
||||
/// ```
|
||||
/// use rand::{SeedableRng, thread_rng};
|
||||
/// use rand::rngs::SmallRng;
|
||||
///
|
||||
/// // Create a big, expensive to initialize and slower, but unpredictable RNG.
|
||||
/// // This is cached and done only once per thread.
|
||||
/// let mut thread_rng = thread_rng();
|
||||
/// // Create small, cheap to initialize and fast RNGs with random seeds.
|
||||
/// // One can generally assume this won't fail.
|
||||
/// let rngs: Vec<SmallRng> = (0..10)
|
||||
/// .map(|_| SmallRng::from_rng(&mut thread_rng).unwrap())
|
||||
/// .collect();
|
||||
/// ```
|
||||
///
|
||||
/// [`StdRng`]: crate::rngs::StdRng
|
||||
/// [`thread_rng`]: crate::thread_rng
|
||||
/// [rand_chacha]: https://crates.io/crates/rand_chacha
|
||||
/// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "small_rng")))]
|
||||
@@ -102,21 +64,53 @@ impl RngCore for SmallRng {
|
||||
}
|
||||
}
|
||||
|
||||
impl SeedableRng for SmallRng {
|
||||
type Seed = <Rng as SeedableRng>::Seed;
|
||||
|
||||
impl SmallRng {
|
||||
/// Construct an instance seeded from another `Rng`
|
||||
///
|
||||
/// We recommend that the source (master) RNG uses a different algorithm
|
||||
/// (i.e. is not `SmallRng`) to avoid correlations between the child PRNGs.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use rand::rngs::SmallRng;
|
||||
/// let rng = SmallRng::from_rng(rand::thread_rng());
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn from_seed(seed: Self::Seed) -> Self {
|
||||
SmallRng(Rng::from_seed(seed))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
|
||||
pub fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> {
|
||||
Rng::from_rng(rng).map(SmallRng)
|
||||
}
|
||||
|
||||
/// Construct an instance seeded from the thread-local RNG
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This method panics only if [`thread_rng`](crate::thread_rng) fails to
|
||||
/// initialize.
|
||||
#[cfg(all(feature = "std", feature = "std_rng", feature = "getrandom"))]
|
||||
#[inline(always)]
|
||||
fn seed_from_u64(state: u64) -> Self {
|
||||
pub fn from_thread_rng() -> Self {
|
||||
let mut seed = <Rng as SeedableRng>::Seed::default();
|
||||
crate::thread_rng().fill_bytes(seed.as_mut());
|
||||
SmallRng(Rng::from_seed(seed))
|
||||
}
|
||||
|
||||
/// Construct an instance from a `u64` seed
|
||||
///
|
||||
/// This provides a convenient method of seeding a `SmallRng` from a simple
|
||||
/// number by use of another algorithm to mutate and expand the input.
|
||||
/// This is suitable for use with low Hamming Weight numbers like 0 and 1.
|
||||
///
|
||||
/// **Warning:** the implementation is deterministic but not portable:
|
||||
/// output values may differ according to platform and may be changed by a
|
||||
/// future version of the library.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use rand::rngs::SmallRng;
|
||||
/// let rng = SmallRng::seed_from_u64(1);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn seed_from_u64(state: u64) -> Self {
|
||||
SmallRng(Rng::seed_from_u64(state))
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -57,7 +57,8 @@ impl RngCore for StdRng {
|
||||
}
|
||||
|
||||
impl SeedableRng for StdRng {
|
||||
type Seed = <Rng as SeedableRng>::Seed;
|
||||
// Fix to 256 bits. Changing this is a breaking change!
|
||||
type Seed = [u8; 32];
|
||||
|
||||
#[inline(always)]
|
||||
fn from_seed(seed: Self::Seed) -> Self {
|
||||
|
||||
Reference in New Issue
Block a user