Skip to content

Commit 4dae8d7

Browse files
committed
Port iter code from dhardy/master
1 parent 5bc4785 commit 4dae8d7

2 files changed

Lines changed: 259 additions & 2 deletions

File tree

‎src/iter.rs‎

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// https://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Iterators over `RngCore`
12+
13+
use core::cmp::min;
14+
use core::usize;
15+
16+
use RngCore;
17+
18+
// TODO: in the future (see https://github.com/rust-lang/rfcs/issues/1403)
19+
// it may be possible to allow reborrows in user code; this would let us
20+
// replace `rng: &'a mut R` with `rng: R` in `Iter`, without having to create a
21+
// redundant reference when calling `Map::next`. In this case `Rng::iter` would
22+
// return `Iter<&mut Self>` and a separate constructor would be needed for
23+
// reference/copy types not needing an extra reference.
24+
25+
/// An "iterator" over a random number generator; created by [`Rng::iter`].
26+
///
27+
/// This does not implement `std::iter::Iterator` since we cannot support
28+
/// `next()`: it makes no sense to return a copy of an RNG, and though in
29+
/// theory it should be possible to return `&mut RngCore`, `Iterator` does not
30+
/// allow the lifetime of the item returned by `next` to be linked to the
31+
/// iterator (or enclosed RNG). Instead, we support other selected operations
32+
/// such as `map` and `take` directly.
33+
///
34+
/// [`Rng::iter`]: ../trait.Rng.html#method.iter
35+
#[derive(Debug)]
36+
pub struct Iter<'a, R: RngCore + ?Sized + 'a> {
37+
pub(crate) rng: &'a mut R,
38+
pub(crate) len: Option<usize>,
39+
}
40+
41+
impl<'a, R: RngCore + ?Sized + 'a> Iter<'a, R> {
42+
pub(crate) fn new(rng: &'a mut R) -> Iter<'a, R> {
43+
Iter { rng, len: None }
44+
}
45+
}
46+
47+
impl<'a, R: RngCore + ?Sized + 'a> Iter<'a, R> {
48+
/// Restricts the number of generated items to at most `len`.
49+
pub fn take(self, len: usize) -> Self {
50+
Iter {
51+
rng: self.rng,
52+
len: Some(self.len.map_or(len, |old| min(old, len))),
53+
}
54+
}
55+
56+
/// Takes a closure and creates an iterator which calls that closure on
57+
/// each element.
58+
///
59+
/// ### Example
60+
///
61+
/// ```rust
62+
/// use rand::{thread_rng, Rng};
63+
/// use rand::distributions::Range;
64+
///
65+
/// let die_range = Range::new(1, 7);
66+
/// let mut rng = thread_rng();
67+
/// let mut die = rng.iter().map(|rng| rng.sample(die_range));
68+
/// for _ in 0..3 {
69+
/// println!("Die roll: {}", die.next().unwrap());
70+
/// }
71+
/// ```
72+
pub fn map<B, F>(self, f: F) -> Map<'a, R, B, F>
73+
where F: FnMut(&mut R) -> B
74+
{
75+
Map {
76+
rng: self.rng,
77+
len: self.len,
78+
f: f,
79+
}
80+
}
81+
82+
/// Creates an iterator that works like map, but flattens nested structure.
83+
///
84+
/// The [`map`] adapter is very useful, but only when the closure argument
85+
/// produces values. If it produces an iterator instead, there's an extra
86+
/// layer of indirection. `flat_map()` will remove this extra layer on its
87+
/// own.
88+
///
89+
/// ### Example
90+
///
91+
/// ```rust
92+
/// use rand::{thread_rng, Rng};
93+
/// use rand::distributions::Range;
94+
///
95+
/// let len_range = Range::new(1, 10);
96+
/// let mut rng = thread_rng();
97+
///
98+
/// // Count from 1 to a number between 1 and 9 several times:
99+
/// let mut iter = rng.iter().flat_map(|rng| 1..rng.sample(len_range)).take(20);
100+
/// while let Some(n) = iter.next() {
101+
/// println!("{}", n);
102+
/// }
103+
/// ```
104+
///
105+
/// [`map`]: struct.Iter.html#method.map
106+
pub fn flat_map<U, F>(self, f: F) -> FlatMap<'a, R, U, F>
107+
where F: FnMut(&mut R) -> U, U: IntoIterator
108+
{
109+
FlatMap {
110+
rng: self.rng,
111+
len: self.len,
112+
f: f,
113+
frontiter: None,
114+
}
115+
}
116+
}
117+
118+
/// Type created by [`Iter::map`](struct.Iter.html#method.map)
119+
#[derive(Debug)]
120+
pub struct Map<'a, R:?Sized+'a, B, F> where F: FnMut(&mut R) -> B {
121+
rng: &'a mut R,
122+
len: Option<usize>,
123+
f: F,
124+
}
125+
impl<'a, R:?Sized+'a, B, F> Iterator for Map<'a, R, B, F>
126+
where F: FnMut(&mut R) -> B
127+
{
128+
type Item = B;
129+
130+
fn next(&mut self) -> Option<B> {
131+
match self.len {
132+
Some(0) => return None,
133+
Some(ref mut n) => { *n -= 1; }
134+
None => {}
135+
}
136+
137+
Some((self.f)(self.rng))
138+
}
139+
140+
fn size_hint(&self) -> (usize, Option<usize>) {
141+
// If len == None we have an infinite iterator; usize::MAX is nearest
142+
// available lower bound. Probably this suffices to make the following equal:
143+
// rng.iter().take(n).map(f).size_hint() == rng.iter().map(f).take(n).size_hint()
144+
self.len.map_or((usize::MAX, None), |len| (len, Some(len)))
145+
}
146+
}
147+
148+
/// Type created by [`Iter::flat_map`](struct.Iter.html#method.flat_map)
149+
#[derive(Debug)]
150+
pub struct FlatMap<'a, R:?Sized+'a, U, F>
151+
where F: FnMut(&mut R) -> U, U: IntoIterator
152+
{
153+
rng: &'a mut R,
154+
len: Option<usize>,
155+
f: F,
156+
frontiter: Option<U::IntoIter>,
157+
}
158+
impl<'a, R:?Sized+'a, U, F> Iterator for FlatMap<'a, R, U, F>
159+
where F: FnMut(&mut R) -> U, U: IntoIterator
160+
{
161+
type Item = <U as IntoIterator>::Item;
162+
163+
fn next(&mut self) -> Option<Self::Item> {
164+
loop {
165+
if let Some(ref mut inner) = self.frontiter {
166+
if let Some(x) = inner.by_ref().next() {
167+
return Some(x)
168+
}
169+
}
170+
171+
match self.len {
172+
Some(0) => return None,
173+
Some(ref mut n) => { *n -= 1; }
174+
None => {}
175+
}
176+
177+
self.frontiter = Some(IntoIterator::into_iter((self.f)(self.rng)));
178+
}
179+
}
180+
181+
fn size_hint(&self) -> (usize, Option<usize>) {
182+
if self.len == Some(0) {
183+
// No new iters, so we have frontiter or nothing
184+
self.frontiter.as_ref().map_or((0, Some(0)), |it| it.size_hint())
185+
} else {
186+
// Can't compute an actual bound without producing the sub-iters,
187+
// which we don't want to do. But we may have a lower bound.
188+
let lb = self.frontiter.as_ref().map_or(0, |it| it.size_hint().0);
189+
(lb, None)
190+
}
191+
}
192+
}
193+
194+
#[cfg(test)]
195+
mod tests {
196+
use {Rng, RngCore};
197+
use distributions::{Uniform};
198+
#[cfg(all(not(feature="std"), feature="alloc"))] use alloc::{Vec, String};
199+
200+
#[test]
201+
#[cfg(any(feature="std", feature="alloc"))]
202+
fn test_iter() {
203+
let mut rng = ::test::rng(160);
204+
205+
let x: Vec<()> = rng.iter().take(10).map(|_| ()).collect();
206+
assert_eq!(x.len(), 10);
207+
let y: Vec<u32> = rng.iter().take(10).map(|rng| rng.sample(Uniform)).collect();
208+
assert_eq!(y.len(), 10);
209+
let z: Vec<u32> = rng.iter().take(10).flat_map(|rng|
210+
vec![rng.sample(Uniform), rng.sample(Uniform)].into_iter()).collect();
211+
assert_eq!(z.len(), 20);
212+
let w: Vec<String> = rng.iter().take(10).flat_map(|_| vec![].into_iter()).collect();
213+
assert_eq!(w.len(), 0);
214+
}
215+
216+
#[test]
217+
fn test_dyn_dispatch() {
218+
let mut rng = ::test::rng(161);
219+
let mut r: &mut RngCore = &mut rng;
220+
221+
let mut x = 0;
222+
for n in r.iter().map(|rng| rng.next_u32()).take(2) {
223+
x ^= n;
224+
}
225+
assert!(x != 0);
226+
}
227+
}

‎src/lib.rs‎

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@
252252
#![cfg_attr(all(target_arch = "wasm32", not(target_os = "emscripten")), recursion_limit="128")]
253253

254254
#[cfg(feature="std")] extern crate std as core;
255-
#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc;
255+
#[cfg(all(feature = "alloc", not(feature="std")))] #[macro_use] extern crate alloc;
256256

257257
#[cfg(test)] #[cfg(feature="serde-1")] extern crate bincode;
258258
#[cfg(feature="serde-1")] extern crate serde;
@@ -296,6 +296,7 @@ use distributions::range::SampleRange;
296296
// public modules
297297
pub mod distributions;
298298
mod impls;
299+
pub mod iter;
299300
pub mod jitter;
300301
pub mod mock;
301302
#[cfg(feature="std")] pub mod os;
@@ -314,9 +315,9 @@ pub mod isaac {
314315
}
315316

316317
// private modules
317-
mod le;
318318
#[cfg(feature="std")] mod entropy_rng;
319319
mod error;
320+
mod le;
320321
mod prng;
321322
#[cfg(feature="std")] mod thread_rng;
322323

@@ -647,6 +648,35 @@ pub trait Rng: RngCore + Sized {
647648
n <= 1 || self.gen_range(0, n) == 0
648649
}
649650

651+
/// Construct an iterator on an `Rng`.
652+
///
653+
/// ### Example
654+
///
655+
/*
656+
/// ```rust
657+
/// use rand::{thread_rng, Rng};
658+
/// use distributions::Range;
659+
///
660+
/// let die_range = Range::new(1, 7);
661+
/// let mut die = thread_rng().iter().map(|rng| rng.sample(die_range));
662+
/// for _ in 0..3 {
663+
/// println!("Die roll: {}", die.next());
664+
/// }
665+
/// ```
666+
*/
667+
/* TODO: Alphanumeric
668+
/// ```rust
669+
/// use rand::{thread_rng, Rng};
670+
/// use rand::distributions::Alphanumeric;
671+
///
672+
/// let mut rng = thread_rng();
673+
/// let x: String = rng.iter().map(|rng| rng.sample(Alphanumeric)).take(6).collect();
674+
/// ```
675+
*/
676+
fn iter<'a>(&'a mut self) -> iter::Iter<'a, Self> {
677+
iter::Iter::new(self)
678+
}
679+
650680
/// Return an iterator of random characters from the set A-Z,a-z,0-9.
651681
///
652682
/// # Example

0 commit comments

Comments
 (0)