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}