diff --git a/src/rng.rs b/src/rng.rs index 79a9fbff46e..676fcb8c7f2 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -8,12 +8,13 @@ // except according to those terms. //! [`Rng`] trait +use core::num::Wrapping; +use core::{mem, slice}; use rand_core::{Error, RngCore}; + use crate::distributions::uniform::{SampleRange, SampleUniform}; use crate::distributions::{self, Distribution, Standard}; -use core::num::Wrapping; -use core::{mem, slice}; /// An automatically-implemented extension trait on [`RngCore`] providing high-level /// generic methods for sampling values and other convenience methods. @@ -91,7 +92,9 @@ pub trait Rng: RngCore { /// [`Standard`]: distributions::Standard #[inline] fn gen(&mut self) -> T - where Standard: Distribution { + where + Standard: Distribution, + { Standard.sample(self) } @@ -129,7 +132,7 @@ pub trait Rng: RngCore { fn gen_range(&mut self, range: R) -> T where T: SampleUniform, - R: SampleRange + R: SampleRange, { assert!(!range.is_empty(), "cannot sample empty range"); range.sample_single(self) @@ -216,7 +219,8 @@ pub trait Rng: RngCore { /// [`fill_bytes`]: RngCore::fill_bytes /// [`try_fill`]: Rng::try_fill fn fill(&mut self, dest: &mut T) { - dest.try_fill(self).unwrap_or_else(|_| panic!("Rng::fill failed")) + dest.try_fill(self) + .unwrap_or_else(|_| panic!("Rng::fill failed")) } /// Fill any type implementing [`Fill`] with random data @@ -316,25 +320,25 @@ pub trait Fill { fn try_fill(&mut self, rng: &mut R) -> Result<(), Error>; } -macro_rules! impl_fill_each { +macro_rules! impl_fill_each_uninit { () => {}; ($t:ty) => { - impl Fill for [$t] { + impl Fill for [mem::MaybeUninit<$t>] { fn try_fill(&mut self, rng: &mut R) -> Result<(), Error> { for elt in self.iter_mut() { - *elt = rng.gen(); + *elt = mem::MaybeUninit::new(rng.gen()); } Ok(()) } } }; ($t:ty, $($tt:ty,)*) => { - impl_fill_each!($t); - impl_fill_each!($($tt,)*); + impl_fill_each_uninit!($t); + impl_fill_each_uninit!($($tt,)*); }; } -impl_fill_each!(bool, char, f32, f64,); +impl_fill_each_uninit!(bool, char, f32, f64,); impl Fill for [u8] { fn try_fill(&mut self, rng: &mut R) -> Result<(), Error> { @@ -392,10 +396,36 @@ macro_rules! impl_fill { impl_fill!(u16, u32, u64, usize, u128,); impl_fill!(i8, i16, i32, i64, isize, i128,); +macro_rules! impl_fill_delegate_to_maybe_uninit{ + () => {}; + ($t:ty) => { + impl Fill for [$t] { + fn try_fill(&mut self, rng: &mut R) -> Result<(), Error> { + Fill::try_fill( + unsafe { + slice::from_raw_parts_mut(self.as_mut_ptr() + as *mut mem::MaybeUninit<$t>, + self.len() + ) + }, + rng, + ) + } + } + }; + ($t:ty, $($tt:ty,)*) => { + impl_fill_delegate_to_maybe_uninit!($t); + impl_fill_delegate_to_maybe_uninit!($($tt,)*); + }; +} + +impl_fill_delegate_to_maybe_uninit!(bool, char, f32, f64,); + #[cfg_attr(doc_cfg, doc(cfg(feature = "min_const_gen")))] #[cfg(feature = "min_const_gen")] impl Fill for [T; N] -where [T]: Fill +where + [T]: Fill, { fn try_fill(&mut self, rng: &mut R) -> Result<(), Error> { self[..].try_fill(rng) @@ -431,9 +461,10 @@ impl_fill_arrays!(!div 4096, N,N,N,N,N,N,N,); #[cfg(test)] mod test { use super::*; - use crate::test::rng; use crate::rngs::mock::StepRng; - #[cfg(feature = "alloc")] use alloc::boxed::Box; + use crate::test::rng; + #[cfg(feature = "alloc")] + use alloc::boxed::Box; #[test] fn test_fill_bytes_default() { @@ -485,6 +516,25 @@ mod test { assert_eq!(array, gen); } + #[test] + fn test_gen_range_uninit_same_as_simple() { + let mut r = rng(101); + let mut mu_array: [mem::MaybeUninit; 64] = unsafe { + // Safe to assume init because inner values have uninit type. + mem::MaybeUninit::uninit().assume_init() + }; + r.fill(&mut mu_array); + + let mut r = rng(101); + let mut array = ['\0'; 64]; + r.fill(&mut array); + + assert!(mu_array.iter().zip(&array).all(|(&a, &b)| unsafe { + // This assume_init should trigger Miri if we done something wrong + a.assume_init() == b + })) + } + #[test] fn test_fill_empty() { let mut array = [0u32; 0];