choosen/
lib.rs

1use reservoir_sampler::{Reservoir, ReservoirSampler};
2
3mod builder;
4mod pos;
5
6pub use crate::builder::{BuildChoosenError, ChoosenBuilder};
7pub use crate::pos::{Position, PositionType, PositionTypeError};
8
9#[derive(Clone, Copy, PartialEq, Debug)]
10pub enum ChoosenError {
11    NoOneIsChoosen,
12}
13
14pub struct Choosen<P, PT = Position>
15where
16    PT: PositionType,
17{
18    positions: Vec<PT>,
19    lucky: Reservoir<P>,
20}
21
22impl<P, PT> Choosen<P, PT>
23where
24    PT: PositionType,
25{
26    pub fn poll_one(&mut self, it: P) -> (usize, usize, Option<P>) {
27        self.lucky.sample(it)
28    }
29
30    pub fn lucky(&self) -> &[Option<P>] {
31        self.lucky.samples()
32    }
33
34    pub fn release(self) -> Result<Vec<(String, Vec<P>)>, ChoosenError> {
35        let mut final_lucky = self.lucky.lock();
36
37        if !final_lucky.iter().any(|it| it.is_some()) {
38            return Err(ChoosenError::NoOneIsChoosen);
39        }
40
41        let mut counted = 0;
42        let mut result = Vec::new();
43        for p in self.positions {
44            let mut luck = Vec::with_capacity(p.cap());
45
46            for i in 0..p.cap() {
47                if let Some(it) = final_lucky[counted + i].take() {
48                    luck.push(it);
49                }
50            }
51
52            result.push((p.name().into(), luck));
53            counted += p.cap();
54        }
55
56        Ok(result)
57    }
58}
59
60#[cfg(test)]
61mod test {
62    use super::*;
63    #[test]
64    fn have_something_choosen() -> Result<(), BuildChoosenError> {
65        let v = vec![8, 1, 1, 9, 2];
66        let mut choosen = ChoosenBuilder::<Position>::new()
67            .add_position("一等奖", 1)?
68            .add_position("二等奖", 1)?
69            .add_position("三等奖", 4)?
70            .build::<usize>()?;
71
72        for it in v {
73            choosen.poll_one(it);
74            println!("{:?}", choosen.lucky());
75        }
76
77        println!("{:?}", choosen.release().unwrap());
78        Ok(())
79    }
80
81    #[test]
82    fn have_nothhing_choosen() -> Result<(), BuildChoosenError> {
83        let choosen = ChoosenBuilder::<Position>::new()
84            .add_position("一等奖", 3)?
85            .add_position("三等奖", 4)?
86            .build::<usize>()?;
87
88        assert_eq!(choosen.release().err(), Some(ChoosenError::NoOneIsChoosen));
89
90        Ok(())
91    }
92}