random_wheel/
random_wheel.rs

1extern crate rand;
2use std::iter::repeat;
3use std::collections::VecDeque;
4use std::collections::vec_deque::{ IntoIter, Iter, IterMut };
5use self::rand::Rng;
6
7/// a little implementation of a random-wheel.
8pub struct RandomWheel<T> {
9    /// the sum of all probabilities in this wheel.
10    proba_sum: f32,
11    /// all the (probability, data) in a linked-list to pop easily.
12    cards: VecDeque<(f32, T)>
13}
14
15impl<T: Clone> Clone for RandomWheel<T> {
16    fn clone(&self) -> RandomWheel<T> {
17        RandomWheel{
18            proba_sum: self.proba_sum,
19            cards: self.cards.clone()
20        }
21    }
22}
23
24impl<T> IntoIterator for RandomWheel<T> {
25
26    type Item = (f32, T);
27    type IntoIter = IntoIter<(f32, T)>;
28
29    /// Creates a consuming iterator, that is, one that moves each value out of
30    /// the randomWheel (from start to end).
31    #[inline]
32    fn into_iter(self) -> IntoIter<(f32, T)> {
33        self.cards.into_iter()
34    }
35}
36
37impl<T> RandomWheel<T> {
38    /// create a new random-wheel from vector.
39    /// # Example
40    ///
41    /// ```
42    /// use random_wheel::RandomWheel;
43    ///
44    /// let numbers: Vec<_> = (0..20).collect();
45    ///
46    /// // default probability is set to 1.0 for each element
47    /// let rw: RandomWheel<u8> = RandomWheel::from_vec(numbers);
48    /// ```
49    pub fn from_vec(vector: Vec<T>) -> RandomWheel<T> {
50
51        RandomWheel {
52
53            proba_sum: vector.len() as f32,
54            cards: repeat(1.0).into_iter().zip(vector).collect()
55        }
56    }
57
58    /// create a new empty random-wheel.
59    /// # Example
60    ///
61    /// ```
62    /// use random_wheel::RandomWheel;
63    ///
64    /// let rw: RandomWheel<u8> = RandomWheel::new();
65    /// ```
66    pub fn new() -> RandomWheel<T> {
67
68        RandomWheel {
69
70            proba_sum: 0.,
71            cards: VecDeque::new()
72        }
73    }
74
75    /// Creates an empty RandomWheel with space for at least n elements.
76    /// # Example
77    ///
78    /// ```
79    /// use random_wheel::RandomWheel;
80    ///
81    /// let numbers: Vec<_> = (0..20).collect();
82    /// let mut rw: RandomWheel<u8> = RandomWheel::with_capacity(numbers.len());
83    ///
84    /// assert_eq!(rw.len(), 0);
85    /// ```
86    pub fn with_capacity(n: usize) -> RandomWheel<T> {
87
88        RandomWheel {
89
90            proba_sum: 0.,
91            cards: VecDeque::with_capacity(n)
92        }
93    }
94
95    /// Reserves capacity for at least `additional` more elements to be inserted
96    /// in the given `Ringbuf`.
97    /// The collection may reserve more space to avoid frequent reallocations.
98    /// # Example
99    ///
100    /// ```
101    /// use random_wheel::RandomWheel;
102    ///
103    /// let mut rw: RandomWheel<u8> = RandomWheel::new();
104    /// rw.reserve(20);
105    ///
106    /// assert_eq!(rw.len(), 0);
107    /// ```
108    pub fn reserve(&mut self, additional: usize) {
109        self.cards.reserve(additional);
110    }
111
112    /// Returns the number of elements the RandomWheel can hold without
113    /// reallocating.
114    /// # Example
115    ///
116    /// ```
117    /// use random_wheel::RandomWheel;
118    ///
119    /// let rw: RandomWheel<u8> = RandomWheel::new();
120    ///
121    /// println!("actual capacity: {}", rw.capacity());
122    /// ```
123    pub fn capacity(&self) -> usize {
124        self.cards.capacity()
125    }
126
127    /// returns the number of elements in the wheel.
128    /// # Example
129    ///
130    /// ```
131    /// use random_wheel::RandomWheel;
132    ///
133    /// let mut rw = RandomWheel::new();
134    ///
135    /// assert_eq!(rw.len(), 0);
136    ///
137    /// rw.push(1., 'r');
138    /// rw.push(1., 'c');
139    /// rw.push(1., 'a');
140    ///
141    /// assert_eq!(rw.len(), 3);
142    /// ```
143    pub fn len(&self) -> usize {
144        self.cards.len()
145    }
146
147    /// remove all elements in this wheel.
148    /// # Example
149    ///
150    /// ```
151    /// use random_wheel::RandomWheel;
152    ///
153    /// let mut rw = RandomWheel::new();
154    ///
155    /// rw.push(1., 'r');
156    /// rw.push(1., 'c');
157    /// rw.push(1., 'a');
158    ///
159    /// assert_eq!(rw.len(), 3);
160    ///
161    /// rw.clear();
162    ///
163    /// assert_eq!(rw.len(), 0);
164    /// ```
165    pub fn clear(&mut self) {
166        self.cards.clear()
167    }
168
169    /// returns `true` if this wheel is empty else return `false`.
170    /// # Example
171    ///
172    /// ```
173    /// use random_wheel::RandomWheel;
174    ///
175    /// let mut rw = RandomWheel::new();
176    ///
177    /// assert_eq!(rw.is_empty(), true);
178    ///
179    /// rw.push(1., 'r');
180    /// rw.push(1., 'c');
181    /// rw.push(1., 'a');
182    ///
183    /// assert_eq!(rw.is_empty(), false);
184    /// ```
185    pub fn is_empty(&self) -> bool {
186        self.len() == 0
187    }
188
189    /// Returns an iterator over the slice.
190    /// # Example
191    ///
192    /// ```
193    /// use random_wheel::RandomWheel;
194    ///
195    /// let mut rw = RandomWheel::new();
196    ///
197    /// rw.push(1., 'r');
198    /// rw.push(1., 'c');
199    /// rw.push(1., 'a');
200    ///
201    /// let mut iter = rw.iter();
202    ///
203    /// assert_eq!(iter.next(), Some(&(1.0, 'r')));
204    /// assert_eq!(iter.next(), Some(&(1.0, 'c')));
205    /// assert_eq!(iter.next(), Some(&(1.0, 'a')));
206    /// assert_eq!(iter.next(), None);
207    /// ```
208    pub fn iter(&self) -> Iter<(f32, T)> {
209        self.cards.iter()
210    }
211
212    /// Returns an iterator that allows modifying each value.
213    /// # Example
214    ///
215    /// ```
216    /// use random_wheel::RandomWheel;
217    ///
218    /// let mut rw = RandomWheel::new();
219    ///
220    /// rw.push(1., 'r');
221    /// rw.push(1., 'c');
222    /// rw.push(1., 'a');
223    ///
224    /// for a in &mut rw.iter_mut() {
225    ///     a.1 = 'm';
226    /// }
227    ///
228    /// assert_eq!(rw.peek(), Some((1., &'m')));
229    /// ```
230    pub fn iter_mut(&mut self) -> IterMut<(f32, T)> {
231        self.cards.iter_mut()
232    }
233
234    /// add an element associated with a probability.
235    /// # Example
236    ///
237    /// ```
238    /// use random_wheel::RandomWheel;
239    ///
240    /// let mut rw = RandomWheel::new();
241    ///
242    /// rw.push(1., 'r');
243    /// rw.push(1., 'c');
244    /// rw.push(1., 'a');
245    ///
246    /// assert_eq!(rw.len(), 3);
247    /// ```
248    pub fn push(&mut self, proba: f32, data: T) {
249
250        assert!(proba > 0.0, "proba {} is lower or equal to zero!", proba);
251        self.cards.push_back((proba, data));
252        self.proba_sum += proba;
253        if self.proba_sum.is_infinite() {
254            panic!("Probability sum reached an Inf value!");
255        }
256    }
257
258    /// Will recompute the probabilities sum
259    /// use it when you iterate through this vector and change proba values
260    pub fn compute_proba_sum(&mut self) {
261
262        let mut sum = 0.0;
263        for &(proba, _) in self.cards.iter() {
264
265            assert!(proba > 0.0, "proba {} is lower or equal to zero!", proba);
266            sum += proba;
267        }
268        self.proba_sum = sum;
269        if self.proba_sum.is_infinite() {
270            panic!("Probability sum reached an Inf value!");
271        }
272    }
273
274    /// returns total of luck you pushed.
275    /// # Example
276    ///
277    /// ```
278    /// use random_wheel::RandomWheel;
279    ///
280    /// let mut rw = RandomWheel::new();
281    ///
282    /// rw.push(1.5, 'r');
283    /// rw.push(2., 'c');
284    /// rw.push(3., 'a');
285    ///
286    /// assert_eq!(rw.proba_sum(), 6.5);
287    /// ```
288    pub fn proba_sum(&self) -> f32 {
289        self.proba_sum
290    }
291
292    /// returns a random distance to browser between 0 and the probabilities sum.
293    fn gen_random_dist(&self) -> f32 {
294
295        match self.proba_sum {
296
297            sum if sum > 0. => rand::thread_rng().gen_range(0., sum),
298            _               => 0.
299        }
300    }
301
302    /// returns a random index in self.cards.
303    fn get_random_index(&self) -> Option<usize> {
304
305        if self.is_empty() == false {
306
307            let mut dist = self.gen_random_dist();
308            for (id, &(ref proba, _)) in self.cards.iter().enumerate() {
309
310                dist -= *proba;
311                if dist <= 0. {
312                    return Some(id);
313                }
314            }
315            None
316        }
317        else { None }
318    }
319
320    /// returns a ref to the randomly peeked element with
321    /// it's probality to be peeked.
322    /// # Example
323    ///
324    /// ```
325    /// use random_wheel::RandomWheel;
326    ///
327    /// let mut rw = RandomWheel::new();
328    ///
329    /// rw.push(1., 'r');
330    ///
331    /// assert_eq!(rw.peek(), Some((1.0, &'r')));
332    /// assert_eq!(rw.peek(), Some((1.0, &'r')));
333    /// ```
334    pub fn peek(&self) -> Option<(f32, &T)> {
335
336        if let Some(index) = self.get_random_index() {
337
338            if let Some(&(proba, ref data)) = self.cards.get(index) {
339                Some((proba, data))
340            }
341            else { None }
342        }
343        else { None }
344    }
345
346    /// returns a ref to the randomly peeked element with
347    /// it's probality to be peeked.
348    /// # Example
349    ///
350    /// ```
351    /// use random_wheel::RandomWheel;
352    ///
353    /// let mut rw = RandomWheel::new();
354    ///
355    /// rw.push(1., 'r');
356    ///
357    /// match rw.peek_mut() {
358    ///     Some((_, val)) => *val = 'b',
359    ///     None => {}
360    /// }
361    ///
362    /// assert_eq!(rw.peek(), Some((1.0, &'b')));
363    /// ```
364    pub fn peek_mut(&mut self) -> Option<(f32, &mut T)> {
365
366        if let Some(index) = self.get_random_index() {
367
368            if let Some(&mut (proba, ref mut data)) = self.cards.get_mut(index) {
369                Some((proba, data))
370            }
371            else { None }
372        }
373        else { None }
374    }
375
376    /// removes a randomly peeked element and return it with
377    /// it's probality to be peeked.
378    /// # Example
379    ///
380    /// ```
381    /// use random_wheel::RandomWheel;
382    ///
383    /// let mut rw = RandomWheel::new();
384    ///
385    /// rw.push(1., 'r');
386    ///
387    /// assert_eq!(rw.pop(), Some((1.0, 'r')));
388    ///
389    /// // once you pop the value, it doesn't exist anymore
390    /// assert_eq!(rw.peek(), None);
391    /// assert_eq!(rw.pop(), None);
392    /// ```
393    pub fn pop(&mut self) -> Option<(f32, T)> {
394
395        if let Some(index) = self.get_random_index() {
396
397            if let Some((proba, data)) = self.cards.remove(index) {
398
399                self.proba_sum -= proba;
400                Some((proba, data))
401            }
402            else { None }
403        }
404        else { None }
405    }
406}