open_pql/base/
suit.rs

1use super::*;
2
3/// Enum for Suits
4#[derive(Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Display)]
5pub enum Suit {
6    /// <span class="stab emoji">♠️</span> Spade
7    #[display("s")]
8    S = 0,
9    /// <span class="stab emoji">♥️</span> Heart
10    #[display("h")]
11    H,
12    /// <span class="stab emoji">♦️</span> Diamond
13    #[display("d")]
14    D,
15    /// <span class="stab emoji">♣️</span> Club
16    #[display("c")]
17    C,
18}
19
20impl Suit {
21    /// [ S, H, D, C ]
22    pub const ARR_ALL: [Self; N_SUITS as usize] =
23        [Self::S, Self::H, Self::D, Self::C];
24}
25
26impl TryFrom<char> for Suit {
27    type Error = ParseError;
28
29    fn try_from(c: char) -> Result<Self, Self::Error> {
30        match c {
31            'S' | 's' => Ok(Self::S),
32            'H' | 'h' => Ok(Self::H),
33            'D' | 'd' => Ok(Self::D),
34            'C' | 'c' => Ok(Self::C),
35
36            _ => Err(ParseError::InvalidSuit(c.into())),
37        }
38    }
39}
40
41impl FromStr for Suit {
42    type Err = ParseError;
43
44    fn from_str(s: &str) -> Result<Self, Self::Err> {
45        let mut cs = s.chars().filter(|c| !c.is_whitespace());
46
47        if let Some(c) = cs.next() {
48            if let Ok(s) = Self::try_from(c) {
49                if cs.next().is_none() {
50                    return Ok(s);
51                }
52            }
53        }
54
55        Err(ParseError::InvalidSuit(s.into()))
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    impl Arbitrary for Suit {
64        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
65            *g.choose(&Self::ARR_ALL).unwrap()
66        }
67    }
68
69    #[test]
70    fn test_consts() {
71        assert_eq!(Suit::ARR_ALL, [Suit::S, Suit::H, Suit::D, Suit::C]);
72    }
73
74    #[test]
75    fn test_as_int() {
76        assert_eq!(Suit::S as i8, 0);
77        assert_eq!(Suit::H as i8, 1);
78        assert_eq!(Suit::D as i8, 2);
79        assert_eq!(Suit::C as i8, 3);
80    }
81
82    #[test]
83    fn test_from_char() {
84        assert_eq!(Ok(Suit::S), 's'.try_into());
85        assert_eq!(Ok(Suit::H), 'h'.try_into());
86        assert_eq!(Ok(Suit::D), 'd'.try_into());
87        assert_eq!(Ok(Suit::C), 'c'.try_into());
88
89        assert_eq!(Ok(Suit::S), 'S'.try_into());
90        assert_eq!(Ok(Suit::H), 'H'.try_into());
91        assert_eq!(Ok(Suit::D), 'D'.try_into());
92        assert_eq!(Ok(Suit::C), 'C'.try_into());
93
94        assert_eq!(
95            Err(ParseError::InvalidSuit("?".into())),
96            Suit::try_from('?')
97        );
98    }
99
100    #[test]
101    fn test_from_str() {
102        assert_eq!(Ok(Suit::S), " s ".parse());
103        assert_eq!(
104            Err(ParseError::InvalidSuit("sS".into())),
105            "sS".parse::<Suit>()
106        );
107        assert!("".parse::<Suit>().is_err());
108        assert!("?".parse::<Suit>().is_err());
109    }
110
111    #[test]
112    fn test_to_string() {
113        assert_eq!("s", &Suit::S.to_string());
114        assert_eq!("h", &Suit::H.to_string());
115        assert_eq!("d", &Suit::D.to_string());
116        assert_eq!("c", &Suit::C.to_string());
117    }
118}