rand_pop/
lib.rs

1#![cfg_attr(test, feature(plugin))]
2#![cfg_attr(test, plugin(clippy))]
3
4#[cfg(test)]
5#[macro_use]
6extern crate quickcheck;
7
8extern crate rand;
9use rand::Rng;
10
11
12/// Interface for randomly removing elements from a container.
13pub trait RandPop: Sized {
14    /// Type of the item that's removed from the container.
15    type Item;
16
17    /// Randomly removes an item from the container; does not necessarily preserve order.
18    fn rand_pop<R: Rng>(&mut self, rng: &mut R) -> Option<Self::Item>;
19
20    /// Randomly iterates through the items in this container, consuming the container.
21    #[inline]
22    fn rand_iter<R: Rng>(self, rng: &mut R) -> RandIter<Self, R> {
23        RandIter {
24            vals: self,
25            rng: rng,
26        }
27    }
28}
29
30/// Iterator over a container that returns its items in random order.
31pub struct RandIter<'a, C: RandPop, R: 'a + Rng> {
32    vals: C,
33    rng: &'a mut R,
34}
35
36impl<'a, C: RandPop, R: 'a + Rng> Iterator for RandIter<'a, C, R> {
37    type Item = <C as RandPop>::Item;
38    #[inline]
39    fn next(&mut self) -> Option<Self::Item> {
40        self.vals.rand_pop(self.rng)
41    }
42}
43
44impl<T> RandPop for Vec<T> {
45    type Item = T;
46    #[inline]
47    fn rand_pop<R: Rng>(&mut self, rng: &mut R) -> Option<T> {
48        match self.len() {
49            0 => None,
50            l => Some(self.swap_remove(rng.gen_range(0, l))),
51        }
52    }
53}
54
55
56#[cfg(test)]
57mod tests {
58    use rand;
59    use super::*;
60
61    quickcheck! {
62        fn rand_pop(orig: Vec<usize>) -> bool {
63            let mut from = orig.clone();
64            let mut rng = rand::thread_rng();
65
66            let mut to = Vec::new();
67            while let Some(val) = from.rand_pop(&mut rng) {
68                to.push(val);
69            }
70            to.sort();
71
72            let mut orig = orig;
73            orig.sort();
74
75            return from.is_empty() && to == orig;
76        }
77
78        fn rand_iter(orig: Vec<usize>) -> bool {
79            let from = orig.clone();
80            let mut rng = rand::thread_rng();
81
82            let mut to: Vec<usize> = from.rand_iter(&mut rng).collect();
83            to.sort();
84
85            let mut orig = orig;
86            orig.sort();
87
88            return to == orig;
89        }
90    }
91}