rand_core: add blanket impl of TryRngCore for RngCore (#1499)
This PR removes the hacky `impl_try_rng_from_rng_core` and `impl_try_crypto_rng_from_crypto_rng` macros and replaces them with blanket impls of `TryRngCore` for `RngCore` and `TryCryptoRng` for `CryptoRng`. This change means that `TryRngCore`/`TryCryptoRng` no longer can have blanket impls for `&mut R` and `Box<R>`. But I think it should be tolerable since most users will be using `RngCore`/`CryptoRng`, which have blanket impl for `DerefMut` (it covers both `&mut R` and `Box<R>`).
This commit is contained in:
@@ -20,7 +20,7 @@ criterion_main!(benches);
|
||||
|
||||
pub fn bench(c: &mut Criterion) {
|
||||
c.bench_function("seq_slice_choose_1_of_100", |b| {
|
||||
let mut rng = Pcg32::from_rng(thread_rng());
|
||||
let mut rng = Pcg32::from_rng(&mut thread_rng());
|
||||
let mut buf = [0i32; 100];
|
||||
rng.fill(&mut buf);
|
||||
let x = black_box(&mut buf);
|
||||
@@ -32,7 +32,7 @@ pub fn bench(c: &mut Criterion) {
|
||||
for (amount, len) in lens {
|
||||
let name = format!("seq_slice_choose_multiple_{}_of_{}", amount, len);
|
||||
c.bench_function(name.as_str(), |b| {
|
||||
let mut rng = Pcg32::from_rng(thread_rng());
|
||||
let mut rng = Pcg32::from_rng(&mut thread_rng());
|
||||
let mut buf = [0i32; 1000];
|
||||
rng.fill(&mut buf);
|
||||
let x = black_box(&buf[..len]);
|
||||
@@ -53,7 +53,7 @@ pub fn bench(c: &mut Criterion) {
|
||||
}
|
||||
|
||||
c.bench_function("seq_iter_choose_multiple_10_of_100", |b| {
|
||||
let mut rng = Pcg32::from_rng(thread_rng());
|
||||
let mut rng = Pcg32::from_rng(&mut thread_rng());
|
||||
let mut buf = [0i32; 100];
|
||||
rng.fill(&mut buf);
|
||||
let x = black_box(&buf);
|
||||
@@ -61,7 +61,7 @@ pub fn bench(c: &mut Criterion) {
|
||||
});
|
||||
|
||||
c.bench_function("seq_iter_choose_multiple_fill_10_of_100", |b| {
|
||||
let mut rng = Pcg32::from_rng(thread_rng());
|
||||
let mut rng = Pcg32::from_rng(&mut thread_rng());
|
||||
let mut buf = [0i32; 100];
|
||||
rng.fill(&mut buf);
|
||||
let x = black_box(&buf);
|
||||
|
||||
@@ -20,7 +20,7 @@ criterion_main!(benches);
|
||||
|
||||
pub fn bench(c: &mut Criterion) {
|
||||
c.bench_function("seq_shuffle_100", |b| {
|
||||
let mut rng = Pcg32::from_rng(thread_rng());
|
||||
let mut rng = Pcg32::from_rng(&mut thread_rng());
|
||||
let mut buf = [0i32; 100];
|
||||
rng.fill(&mut buf);
|
||||
let x = black_box(&mut buf);
|
||||
|
||||
@@ -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_rng(thread_rng());
|
||||
let mut rng = <$R>::from_rng(&mut thread_rng());
|
||||
let x = rng.random::<$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_rng(thread_rng());
|
||||
let mut rng = <$R>::from_rng(&mut thread_rng());
|
||||
let x = rng.random::<$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_rng(thread_rng());
|
||||
let mut rng = <$R>::from_rng(&mut thread_rng());
|
||||
let (mut low, mut high);
|
||||
loop {
|
||||
low = <$T>::from_bits(rng.random());
|
||||
@@ -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_rng(thread_rng());
|
||||
let mut rng = <$R>::from_rng(&mut thread_rng());
|
||||
let dist = loop {
|
||||
let low = <$T>::from_bits(rng.random());
|
||||
let high = <$T>::from_bits(rng.random());
|
||||
|
||||
@@ -53,7 +53,7 @@ pub fn bench(c: &mut Criterion) {
|
||||
c.bench_function(name.as_str(), |b| {
|
||||
let length = black_box(length);
|
||||
let amount = black_box(amount);
|
||||
let mut rng = SmallRng::from_rng(thread_rng());
|
||||
let mut rng = SmallRng::from_rng(&mut thread_rng());
|
||||
b.iter(|| sample_weighted(&mut rng, length, |idx| (1 + (idx % 100)) as u32, amount))
|
||||
});
|
||||
}
|
||||
|
||||
@@ -257,8 +257,6 @@ macro_rules! chacha_impl {
|
||||
|
||||
impl CryptoRng for $ChaChaXRng {}
|
||||
|
||||
rand_core::impl_try_crypto_rng_from_crypto_rng!($ChaChaXRng);
|
||||
|
||||
impl From<$ChaChaXCore> for $ChaChaXRng {
|
||||
fn from(core: $ChaChaXCore) -> Self {
|
||||
$ChaChaXRng {
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use crate::{CryptoRng, RngCore, TryCryptoRng, TryRngCore};
|
||||
|
||||
impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R {
|
||||
#[inline(always)]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
R::next_u32(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
R::next_u64(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn fill_bytes(&mut self, dst: &mut [u8]) {
|
||||
R::fill_bytes(self, dst)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {}
|
||||
|
||||
impl<'a, R: TryRngCore + ?Sized> TryRngCore for &'a mut R {
|
||||
type Error = R::Error;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
|
||||
R::try_next_u32(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
|
||||
R::try_next_u64(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
|
||||
R::try_fill_bytes(self, dst)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: TryCryptoRng + ?Sized> TryCryptoRng for &'a mut R {}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<R: RngCore + ?Sized> RngCore for Box<R> {
|
||||
#[inline(always)]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
R::next_u32(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
R::next_u64(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
R::fill_bytes(self, dest)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<R: TryRngCore + ?Sized> TryRngCore for Box<R> {
|
||||
type Error = R::Error;
|
||||
|
||||
#[inline(always)]
|
||||
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
|
||||
R::try_next_u32(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
|
||||
R::try_next_u64(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
|
||||
R::try_fill_bytes(self, dst)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<R: TryCryptoRng + ?Sized> TryCryptoRng for Box<R> {}
|
||||
@@ -250,12 +250,12 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn from_rng(rng: impl RngCore) -> Self {
|
||||
fn from_rng(rng: &mut impl RngCore) -> Self {
|
||||
Self::new(R::from_rng(rng))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_from_rng<S: TryRngCore>(rng: S) -> Result<Self, S::Error> {
|
||||
fn try_from_rng<S: TryRngCore>(rng: &mut S) -> Result<Self, S::Error> {
|
||||
R::try_from_rng(rng).map(Self::new)
|
||||
}
|
||||
}
|
||||
@@ -415,12 +415,12 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn from_rng(rng: impl RngCore) -> Self {
|
||||
fn from_rng(rng: &mut impl RngCore) -> Self {
|
||||
Self::new(R::from_rng(rng))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_from_rng<S: TryRngCore>(rng: S) -> Result<Self, S::Error> {
|
||||
fn try_from_rng<S: TryRngCore>(rng: &mut S) -> Result<Self, S::Error> {
|
||||
R::try_from_rng(rng).map(Self::new)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,60 +160,6 @@ pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
|
||||
u64::from_le_bytes(buf)
|
||||
}
|
||||
|
||||
/// Implement [`TryRngCore`][crate::TryRngCore] for a type implementing [`RngCore`].
|
||||
///
|
||||
/// Ideally, `rand_core` would define blanket impls for this, but they conflict with blanket impls
|
||||
/// for `&mut R` and `Box<R>`, so until specialziation is stabilized, implementer crates
|
||||
/// have to implement `TryRngCore` directly.
|
||||
#[macro_export]
|
||||
macro_rules! impl_try_rng_from_rng_core {
|
||||
($t:ty) => {
|
||||
impl $crate::TryRngCore for $t {
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
#[inline]
|
||||
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
|
||||
Ok($crate::RngCore::next_u32(self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
|
||||
Ok($crate::RngCore::next_u64(self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
|
||||
$crate::RngCore::fill_bytes(self, dst);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement [`TryCryptoRng`] and [`TryRngCore`] for a type implementing [`CryptoRng`].
|
||||
///
|
||||
/// Ideally, `rand_core` would define blanket impls for this, but they conflict with blanket impls
|
||||
/// for `&mut R` and `Box<R>`, so until specialziation is stabilized, implementer crates
|
||||
/// have to implement `TryRngCore` and `TryCryptoRng` directly.
|
||||
///
|
||||
/// [`TryCryptoRng`]: crate::TryCryptoRng
|
||||
/// [`TryRngCore`]: crate::TryRngCore
|
||||
/// [`CryptoRng`]: crate::CryptoRng
|
||||
#[macro_export]
|
||||
macro_rules! impl_try_crypto_rng_from_crypto_rng {
|
||||
($t:ty) => {
|
||||
$crate::impl_try_rng_from_rng_core!($t);
|
||||
|
||||
impl $crate::TryCryptoRng for $t {}
|
||||
|
||||
/// Check at compile time that `$t` implements `CryptoRng`
|
||||
const _: () = {
|
||||
const fn check_crypto_rng_impl<T: $crate::CryptoRng>() {}
|
||||
check_crypto_rng_impl::<$t>();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
+60
-13
@@ -40,9 +40,8 @@ extern crate alloc;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
use core::fmt;
|
||||
use core::{fmt, ops::DerefMut};
|
||||
|
||||
mod blanket_impls;
|
||||
pub mod block;
|
||||
pub mod impls;
|
||||
pub mod le;
|
||||
@@ -83,9 +82,9 @@ pub use os::OsRng;
|
||||
/// in this trait directly, then use the helper functions from the
|
||||
/// [`impls`] module to implement the other methods.
|
||||
///
|
||||
/// Implementors of [`RngCore`] SHOULD also implement the [`TryRngCore`]
|
||||
/// trait with the `Error` associated type being equal to [`Infallible`].
|
||||
/// It can be done using the [`impl_try_rng_from_rng_core!`] macro.
|
||||
/// Note that implementors of [`RngCore`] also automatically implement
|
||||
/// the [`TryRngCore`] trait with the `Error` associated type being
|
||||
/// equal to [`Infallible`].
|
||||
///
|
||||
/// It is recommended that implementations also implement:
|
||||
///
|
||||
@@ -125,8 +124,6 @@ pub use os::OsRng;
|
||||
/// impls::fill_bytes_via_next(self, dst)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// rand_core::impl_try_rng_from_rng_core!(CountingRng);
|
||||
/// ```
|
||||
///
|
||||
/// [`rand::Rng`]: https://docs.rs/rand/latest/rand/trait.Rng.html
|
||||
@@ -162,13 +159,29 @@ pub trait RngCore {
|
||||
fn fill_bytes(&mut self, dst: &mut [u8]);
|
||||
}
|
||||
|
||||
impl<T: DerefMut> RngCore for T
|
||||
where
|
||||
T::Target: RngCore,
|
||||
{
|
||||
#[inline]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.deref_mut().next_u32()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.deref_mut().next_u64()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fill_bytes(&mut self, dst: &mut [u8]) {
|
||||
self.deref_mut().fill_bytes(dst);
|
||||
}
|
||||
}
|
||||
|
||||
/// A marker trait used to indicate that an [`RngCore`] implementation is
|
||||
/// supposed to be cryptographically secure.
|
||||
///
|
||||
/// Implementors of [`CryptoRng`] SHOULD also implement the [`TryCryptoRng`]
|
||||
/// trait with the `Error` associated type being equal to [`Infallible`].
|
||||
/// It can be done using the [`impl_try_crypto_rng_from_crypto_rng!`] macro.
|
||||
///
|
||||
/// *Cryptographically secure generators*, also known as *CSPRNGs*, should
|
||||
/// satisfy an additional properties over other generators: given the first
|
||||
/// *k* bits of an algorithm's output
|
||||
@@ -187,10 +200,15 @@ pub trait RngCore {
|
||||
/// Note also that use of a `CryptoRng` does not protect against other
|
||||
/// weaknesses such as seeding from a weak entropy source or leaking state.
|
||||
///
|
||||
/// Note that implementors of [`CryptoRng`] also automatically implement
|
||||
/// the [`TryCryptoRng`] trait.
|
||||
///
|
||||
/// [`BlockRngCore`]: block::BlockRngCore
|
||||
/// [`Infallible`]: core::convert::Infallible
|
||||
pub trait CryptoRng: RngCore {}
|
||||
|
||||
impl<T: DerefMut> CryptoRng for T where T::Target: CryptoRng {}
|
||||
|
||||
/// A potentially fallible version of [`RngCore`].
|
||||
///
|
||||
/// This trait is primarily used for IO-based generators such as [`OsRng`].
|
||||
@@ -233,26 +251,54 @@ pub trait TryRngCore {
|
||||
}
|
||||
}
|
||||
|
||||
// Note that, unfortunately, this blanket impl prevents us from implementing
|
||||
// `TryRngCore` for types which can be dereferenced to `TryRngCore`, i.e. `TryRngCore`
|
||||
// will not be automatically implemented for `&mut R`, `Box<R>`, etc.
|
||||
impl<R: RngCore> TryRngCore for R {
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
#[inline]
|
||||
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
|
||||
Ok(self.next_u32())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
|
||||
Ok(self.next_u64())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.fill_bytes(dst);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A marker trait used to indicate that a [`TryRngCore`] implementation is
|
||||
/// supposed to be cryptographically secure.
|
||||
///
|
||||
/// See [`CryptoRng`] docs for more information about cryptographically secure generators.
|
||||
pub trait TryCryptoRng: TryRngCore {}
|
||||
|
||||
impl<R: CryptoRng> TryCryptoRng for R {}
|
||||
|
||||
/// Wrapper around [`TryRngCore`] implementation which implements [`RngCore`]
|
||||
/// by panicking on potential errors.
|
||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub struct UnwrapErr<R: TryRngCore>(pub R);
|
||||
|
||||
impl<R: TryRngCore> RngCore for UnwrapErr<R> {
|
||||
#[inline]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.0.try_next_u32().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.0.try_next_u64().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fill_bytes(&mut self, dst: &mut [u8]) {
|
||||
self.0.try_fill_bytes(dst).unwrap()
|
||||
}
|
||||
@@ -416,7 +462,7 @@ pub trait SeedableRng: Sized {
|
||||
/// (in prior versions this was not required).
|
||||
///
|
||||
/// [`rand`]: https://docs.rs/rand
|
||||
fn from_rng(mut rng: impl RngCore) -> Self {
|
||||
fn from_rng(rng: &mut impl RngCore) -> Self {
|
||||
let mut seed = Self::Seed::default();
|
||||
rng.fill_bytes(seed.as_mut());
|
||||
Self::from_seed(seed)
|
||||
@@ -425,7 +471,7 @@ pub trait SeedableRng: Sized {
|
||||
/// Create a new PRNG seeded from a potentially fallible `Rng`.
|
||||
///
|
||||
/// See [`from_rng`][SeedableRng::from_rng] docs for more information.
|
||||
fn try_from_rng<R: TryRngCore>(mut rng: R) -> Result<Self, R::Error> {
|
||||
fn try_from_rng<R: TryRngCore>(rng: &mut R) -> Result<Self, R::Error> {
|
||||
let mut seed = Self::Seed::default();
|
||||
rng.try_fill_bytes(seed.as_mut())?;
|
||||
Ok(Self::from_seed(seed))
|
||||
@@ -492,6 +538,7 @@ pub struct RngReadAdapter<'a, R: TryRngCore + ?Sized> {
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<R: TryRngCore + ?Sized> std::io::Read for RngReadAdapter<'_, R> {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
|
||||
self.inner.try_fill_bytes(buf).map_err(|err| {
|
||||
std::io::Error::new(std::io::ErrorKind::Other, std::format!("RNG error: {err}"))
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
//!
|
||||
//! ```
|
||||
//! use rand::prelude::*;
|
||||
//! # let mut r = StdRng::from_rng(thread_rng());
|
||||
//! # let mut r = StdRng::from_rng(&mut thread_rng());
|
||||
//! # let _: f32 = r.random();
|
||||
//! ```
|
||||
|
||||
|
||||
@@ -75,8 +75,6 @@ impl RngCore for StepRng {
|
||||
}
|
||||
}
|
||||
|
||||
rand_core::impl_try_rng_from_rng_core!(StepRng);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(any(feature = "alloc", feature = "serde"))]
|
||||
|
||||
@@ -113,8 +113,6 @@ impl RngCore for SmallRng {
|
||||
}
|
||||
}
|
||||
|
||||
rand_core::impl_try_rng_from_rng_core!(SmallRng);
|
||||
|
||||
impl SmallRng {
|
||||
/// Construct an instance seeded from the thread-local RNG
|
||||
///
|
||||
|
||||
@@ -91,8 +91,6 @@ impl SeedableRng for StdRng {
|
||||
|
||||
impl CryptoRng for StdRng {}
|
||||
|
||||
rand_core::impl_try_crypto_rng_from_crypto_rng!(StdRng);
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::rngs::StdRng;
|
||||
|
||||
@@ -170,8 +170,6 @@ impl RngCore for ThreadRng {
|
||||
|
||||
impl CryptoRng for ThreadRng {}
|
||||
|
||||
rand_core::impl_try_crypto_rng_from_crypto_rng!(ThreadRng);
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
|
||||
@@ -99,8 +99,6 @@ impl RngCore for Xoshiro128PlusPlus {
|
||||
}
|
||||
}
|
||||
|
||||
rand_core::impl_try_rng_from_rng_core!(Xoshiro128PlusPlus);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Xoshiro128PlusPlus;
|
||||
|
||||
@@ -101,8 +101,6 @@ impl RngCore for Xoshiro256PlusPlus {
|
||||
}
|
||||
}
|
||||
|
||||
rand_core::impl_try_rng_from_rng_core!(Xoshiro256PlusPlus);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Xoshiro256PlusPlus;
|
||||
|
||||
Reference in New Issue
Block a user