diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index ada0c1ebece..dddcfc20045 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -182,29 +182,35 @@ pub trait Distribution { /// Create an iterator that generates random values of `T`, using `rng` as /// the source of randomness. /// + /// Note that this function takes `self` by value. This works since + /// `Distribution` is impl'd for `&D` where `D: Distribution`, + /// however borrowing is not automatic hence `distr.sample_iter(...)` may + /// need to be replaced with `(&distr).sample_iter(...)` to borrow or + /// `(&*distr).sample_iter(...)` to reborrow an existing reference. + /// /// # Example /// /// ``` /// use rand::thread_rng; /// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard}; /// - /// let mut rng = thread_rng(); + /// let rng = thread_rng(); /// /// // Vec of 16 x f32: - /// let v: Vec = Standard.sample_iter(&mut rng).take(16).collect(); + /// let v: Vec = Standard.sample_iter(rng).take(16).collect(); /// /// // String: - /// let s: String = Alphanumeric.sample_iter(&mut rng).take(7).collect(); + /// let s: String = Alphanumeric.sample_iter(rng).take(7).collect(); /// /// // Dice-rolling: /// let die_range = Uniform::new_inclusive(1, 6); - /// let mut roll_die = die_range.sample_iter(&mut rng); + /// let mut roll_die = die_range.sample_iter(rng); /// while roll_die.next().unwrap() != 6 { /// println!("Not a 6; rolling again!"); /// } /// ``` - fn sample_iter<'a, R>(&'a self, rng: &'a mut R) -> DistIter<'a, Self, R, T> - where Self: Sized, R: Rng + fn sample_iter(self, rng: R) -> DistIter + where R: Rng, Self: Sized { DistIter { distr: self, @@ -229,20 +235,23 @@ impl<'a, T, D: Distribution> Distribution for &'a D { /// /// [`sample_iter`]: Distribution::sample_iter #[derive(Debug)] -pub struct DistIter<'a, D: 'a, R: 'a, T> { - distr: &'a D, - rng: &'a mut R, +pub struct DistIter { + distr: D, + rng: R, phantom: ::core::marker::PhantomData, } -impl<'a, D, R, T> Iterator for DistIter<'a, D, R, T> - where D: Distribution, R: Rng + 'a +impl Iterator for DistIter + where D: Distribution, R: Rng { type Item = T; #[inline(always)] fn next(&mut self) -> Option { - Some(self.distr.sample(self.rng)) + // Here, self.rng may be a reference, but we must take &mut anyway. + // Even if sample could take an R: Rng by value, we would need to do this + // since Rng is not copyable and we cannot enforce that this is "reborrowable". + Some(self.distr.sample(&mut self.rng)) } fn size_hint(&self) -> (usize, Option) { @@ -251,12 +260,12 @@ impl<'a, D, R, T> Iterator for DistIter<'a, D, R, T> } #[cfg(rustc_1_26)] -impl<'a, D, R, T> iter::FusedIterator for DistIter<'a, D, R, T> - where D: Distribution, R: Rng + 'a {} +impl iter::FusedIterator for DistIter + where D: Distribution, R: Rng {} #[cfg(features = "nightly")] -impl<'a, D, R, T> iter::TrustedLen for DistIter<'a, D, R, T> - where D: Distribution, R: Rng + 'a {} +impl iter::TrustedLen for DistIter + where D: Distribution, R: Rng {} /// A generic random value distribution, implemented for many primitive types. @@ -340,7 +349,8 @@ pub struct Standard; #[cfg(all(test, feature = "std"))] mod tests { - use super::Distribution; + use ::Rng; + use super::{Distribution, Uniform}; #[test] fn test_distributions_iter() { @@ -350,4 +360,22 @@ mod tests { let results: Vec = distr.sample_iter(&mut rng).take(100).collect(); println!("{:?}", results); } + + #[test] + fn test_make_an_iter() { + fn ten_dice_rolls_other_than_five<'a, R: Rng>(rng: &'a mut R) -> impl Iterator + 'a { + Uniform::new_inclusive(1, 6) + .sample_iter(rng) + .filter(|x| *x != 5) + .take(10) + } + + let mut rng = ::test::rng(211); + let mut count = 0; + for val in ten_dice_rolls_other_than_five(&mut rng) { + assert!(val >= 1 && val <= 6 && val != 5); + count += 1; + } + assert_eq!(count, 10); + } } diff --git a/src/lib.rs b/src/lib.rs index 3b59f25086d..1abe3049cf8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -206,35 +206,39 @@ pub trait Rng: RngCore { /// Create an iterator that generates values using the given distribution. /// + /// Note that this function takes its arguments by value. This works since + /// `(&mut R): Rng where R: Rng` and + /// `(&D): Distribution where D: Distribution`, + /// however borrowing is not automatic hence `rng.sample_iter(...)` may + /// need to be replaced with `(&mut rng).sample_iter(...)`. + /// /// # Example /// /// ``` /// use rand::{thread_rng, Rng}; /// use rand::distributions::{Alphanumeric, Uniform, Standard}; /// - /// let mut rng = thread_rng(); + /// let rng = thread_rng(); /// /// // Vec of 16 x f32: - /// let v: Vec = thread_rng().sample_iter(&Standard).take(16).collect(); + /// let v: Vec = rng.sample_iter(Standard).take(16).collect(); /// /// // String: - /// let s: String = rng.sample_iter(&Alphanumeric).take(7).collect(); + /// let s: String = rng.sample_iter(Alphanumeric).take(7).collect(); /// /// // Combined values - /// println!("{:?}", thread_rng().sample_iter(&Standard).take(5) + /// println!("{:?}", rng.sample_iter(Standard).take(5) /// .collect::>()); /// /// // Dice-rolling: /// let die_range = Uniform::new_inclusive(1, 6); - /// let mut roll_die = rng.sample_iter(&die_range); + /// let mut roll_die = rng.sample_iter(die_range); /// while roll_die.next().unwrap() != 6 { /// println!("Not a 6; rolling again!"); /// } /// ``` - fn sample_iter<'a, T, D: Distribution>( - &'a mut self, distr: &'a D, - ) -> distributions::DistIter<'a, D, Self, T> - where Self: Sized { + fn sample_iter(self, distr: D) -> distributions::DistIter + where D: Distribution, Self: Sized { distr.sample_iter(self) } diff --git a/src/rngs/thread.rs b/src/rngs/thread.rs index 8b86ed843fe..f2312e4cbbe 100644 --- a/src/rngs/thread.rs +++ b/src/rngs/thread.rs @@ -67,7 +67,7 @@ const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB /// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng /// [`StdRng`]: crate::rngs::StdRng /// [HC-128]: rand_hc::Hc128Rng -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub struct ThreadRng { // use of raw pointer implies type is neither Send nor Sync rng: *mut ReseedingRng,