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
12pub trait RandPop: Sized {
14 type Item;
16
17 fn rand_pop<R: Rng>(&mut self, rng: &mut R) -> Option<Self::Item>;
19
20 #[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
30pub 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}