Skip to main content

opql/types/
pql_range.rs

1use super::*;
2
3pub struct PQLRange(pub(crate) FnCheckRange, RangeSrc, PQLGame);
4
5impl fmt::Debug for PQLRange {
6    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7        f.debug_tuple("PQLRange")
8            .field(&self.1)
9            .field(&self.2)
10            .finish()
11    }
12}
13
14impl PQLRange {
15    #[inline]
16    pub fn is_satisfied(&self, cs: &[PQLCard]) -> bool {
17        (self.0)(cs)
18    }
19}
20
21/// # Panics
22/// `PQLRange` ensures valid range text
23impl Clone for PQLRange {
24    fn clone(&self) -> Self {
25        (self.2, self.1.as_str()).try_into().unwrap()
26    }
27}
28
29#[cfg(test)]
30impl PQLRange {
31    /// AK != KA but good for assertions in tests
32    pub fn src_eq(&self, other: &Self) -> bool {
33        self.1 == other.1 && self.2 == other.2
34    }
35}
36
37impl TryFrom<(PQLGame, &str)> for PQLRange {
38    type Error = PQLErrorKind;
39
40    fn try_from((game, src): (PQLGame, &str)) -> Result<Self, Self::Error> {
41        fn create_range<const N: usize, const SD: bool>(
42            checker: RangeChecker<N, SD>,
43            src: &str,
44            game: PQLGame,
45        ) -> PQLRange
46        where
47            [u8; N]: smallvec::Array<Item = u8>,
48        {
49            PQLRange(
50                Box::new(move |cs: &[PQLCard]| checker.is_satisfied(cs)),
51                src.to_string(),
52                game,
53            )
54        }
55
56        match game {
57            PQLGame::Holdem => Ok(create_range(
58                RangeChecker::<2, false>::from_src(src)?,
59                src,
60                game,
61            )),
62            PQLGame::Omaha => Ok(create_range(
63                RangeChecker::<4, false>::from_src(src)?,
64                src,
65                game,
66            )),
67            PQLGame::Omaha5 => Ok(create_range(
68                RangeChecker::<5, false>::from_src(src)?,
69                src,
70                game,
71            )),
72            PQLGame::ShortDeck => Ok(create_range(
73                RangeChecker::<2, true>::from_src(src)?,
74                src,
75                game,
76            )),
77        }
78    }
79}
80
81#[cfg(test)]
82pub mod tests {
83    use super::*;
84    use crate::*;
85
86    #[test]
87    fn test_debug() {
88        let range = PQLRange::try_from((PQLGame::default(), "AA")).unwrap();
89
90        assert_eq!(format!("{range:?}"), r#"PQLRange("AA", Holdem)"#);
91    }
92
93    #[test]
94    fn test_err() {
95        for game in [PQLGame::Holdem, PQLGame::Omaha, PQLGame::ShortDeck] {
96            let res = PQLRange::try_from((game, "AAAAK")).unwrap_err();
97
98            assert_eq!(
99                res,
100                RangeError::TooManyCardsInRange((0, "AAAAK".len())).into()
101            );
102        }
103    }
104
105    #[quickcheck]
106    fn test_clone(cards: CardN<2, true>) {
107        let res = PQLRange::try_from((PQLGame::default(), "BB")).unwrap();
108        let cloned = res.clone();
109
110        assert_eq!(
111            res.is_satisfied(cards.as_slice()),
112            cloned.is_satisfied(cards.as_slice()),
113        );
114    }
115}