Skip to main content

openpql_range_parser/ast/
card.rs

1use super::{CardRank, CardSuit, From, RankConst, RankVar, SuitConst, SuitVar};
2
3/// Card pattern within a range, combining rank and suit as concrete, variable, or any.
4#[derive(Copy, Clone, PartialEq, Eq, Debug, derive_more::Display)]
5pub enum RangeCard {
6    /// Concrete rank and concrete suit.
7    #[display("{_0}{_1}")]
8    CC(RankConst, SuitConst),
9    /// Concrete rank and suit variable.
10    #[display("{_0}{_1}")]
11    CV(RankConst, SuitVar),
12    /// Concrete rank with any suit.
13    #[display("{_0}")]
14    CA(RankConst),
15    /// Rank variable and concrete suit.
16    #[display("{_0}{_1}")]
17    VC(RankVar, SuitConst),
18    /// Rank variable and suit variable.
19    #[display("{_0}{_1}")]
20    VV(RankVar, SuitVar),
21    /// Rank variable with any suit.
22    #[display("{_0}")]
23    VA(RankVar),
24    /// Any rank with concrete suit.
25    #[display("{_0}")]
26    AC(SuitConst),
27    /// Any rank with suit variable.
28    #[display("{_0}")]
29    AV(SuitVar),
30    /// Any card.
31    #[display("*")]
32    AA,
33}
34
35impl From<(CardRank, CardSuit)> for RangeCard {
36    fn from(t: (CardRank, CardSuit)) -> Self {
37        match t {
38            (CardRank::Const(r), CardSuit::Const(s)) => Self::CC(r, s),
39            (CardRank::Const(r), CardSuit::Var(s)) => Self::CV(r, s),
40            (CardRank::Var(r), CardSuit::Const(s)) => Self::VC(r, s),
41            (CardRank::Var(r), CardSuit::Var(s)) => Self::VV(r, s),
42            (CardRank::Any, CardSuit::Const(s)) => Self::AC(s),
43            (CardRank::Any, CardSuit::Var(s)) => Self::AV(s),
44        }
45    }
46}
47
48impl From<CardRank> for RangeCard {
49    fn from(r: CardRank) -> Self {
50        match r {
51            CardRank::Const(c) => Self::CA(c),
52            CardRank::Var(v) => Self::VA(v),
53            CardRank::Any => Self::AA,
54        }
55    }
56}
57
58impl From<CardSuit> for RangeCard {
59    fn from(s: CardSuit) -> Self {
60        match s {
61            CardSuit::Const(c) => Self::AC(c),
62            CardSuit::Var(v) => Self::AV(v),
63        }
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use crate::*;
71
72    impl Arbitrary for RangeCard {
73        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
74            match *g.choose(&[0, 1, 2, 3, 4, 5, 6, 7, 8]).unwrap() {
75                0 => Self::CC(RankConst::arbitrary(g), SuitConst::arbitrary(g)),
76                1 => Self::CV(RankConst::arbitrary(g), SuitVar::arbitrary(g)),
77                2 => Self::CA(RankConst::arbitrary(g)),
78                3 => Self::VC(RankVar::arbitrary(g), SuitConst::arbitrary(g)),
79                4 => Self::VV(RankVar::arbitrary(g), SuitVar::arbitrary(g)),
80                5 => Self::VA(RankVar::arbitrary(g)),
81                6 => Self::AC(SuitConst::arbitrary(g)),
82                7 => Self::AV(SuitVar::arbitrary(g)),
83                _ => Self::AA,
84            }
85        }
86    }
87
88    #[test]
89    fn test_card_cc() {
90        assert_range_card("As", "As");
91    }
92
93    #[test]
94    fn test_card_cv() {
95        assert_range_card("Aw", "Aw");
96    }
97
98    #[test]
99    fn test_card_ca() {
100        assert_range_card("A", "A");
101    }
102
103    #[test]
104    fn test_card_vc() {
105        assert_range_card("Bs", "Bs");
106    }
107
108    #[test]
109    fn test_card_vv() {
110        assert_range_card("Bw", "Bw");
111    }
112
113    #[test]
114    fn test_card_va() {
115        assert_range_card("B", "B");
116    }
117
118    #[test]
119    fn test_card_ac() {
120        assert_range_card("s", "s");
121        assert_range_card("*s", "s");
122    }
123
124    #[test]
125    fn test_card_av() {
126        assert_range_card("w", "w");
127        assert_range_card("*w", "w");
128    }
129
130    #[test]
131    fn test_card_aa() {
132        assert_range_card("*", "*");
133    }
134
135    #[quickcheck]
136    fn test_shortdeck(card: RangeCard) {
137        let src = card.to_string();
138        if src.chars().any(|c| ['2', '3', '4', '5'].contains(&c)) {
139            assert!(parse_card_sd(&src).is_err());
140        } else {
141            assert_eq!(Ok(card), parse_card_sd(&src));
142        }
143    }
144
145    fn assert_range_card_sd_err(s: &str, expected: Error) {
146        assert_eq!(parse_card_sd(s), Err(expected.into()));
147    }
148
149    #[test]
150    fn test_shortdeck_error() {
151        assert_range_card_sd_err("2", Error::InvalidRank((0, 1)));
152        assert_range_card_sd_err("3", Error::InvalidRank((0, 1)));
153        assert_range_card_sd_err("4", Error::InvalidRank((0, 1)));
154        assert_range_card_sd_err("5", Error::InvalidRank((0, 1)));
155    }
156}