open_pql/base/
rank.rs

1use super::*;
2
3/// Enum for Ranks
4#[derive(
5    Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Display, Default,
6)]
7pub enum Rank {
8    /// Duece
9    #[default]
10    #[display("2")]
11    R2 = 0,
12    /// Three
13    #[display("3")]
14    R3,
15    /// Four
16    #[display("4")]
17    R4,
18    /// Five
19    #[display("5")]
20    R5,
21    /// Six
22    #[display("6")]
23    R6,
24    /// Seven
25    #[display("7")]
26    R7,
27    /// Eight
28    #[display("8")]
29    R8,
30    /// Nine
31    #[display("9")]
32    R9,
33    /// Ten
34    #[display("T")]
35    RT,
36    /// Jack
37    #[display("J")]
38    RJ,
39    /// Queen
40    #[display("Q")]
41    RQ,
42    /// King
43    #[display("K")]
44    RK,
45    /// Ace
46    #[display("A")]
47    RA,
48}
49
50impl Rank {
51    /// All possible ranks
52    pub const ARR_ALL: [Self; N_RANKS as usize] = [
53        Self::R2,
54        Self::R3,
55        Self::R4,
56        Self::R5,
57        Self::R6,
58        Self::R7,
59        Self::R8,
60        Self::R9,
61        Self::RT,
62        Self::RJ,
63        Self::RQ,
64        Self::RK,
65        Self::RA,
66    ];
67
68    /// All ranks used in short deck poker
69    pub const ARR_ALL_SHORT: [Self; 9] = [
70        Self::R6,
71        Self::R7,
72        Self::R8,
73        Self::R9,
74        Self::RT,
75        Self::RJ,
76        Self::RQ,
77        Self::RK,
78        Self::RA,
79    ];
80
81    /// Creates a rank from a u8 value (0-12)
82    pub fn from_u8(v: u8) -> Self {
83        debug_assert!(v < N_RANKS, "invalid rank: {v}");
84        unsafe { mem::transmute(v) }
85    }
86
87    pub const fn from_char(c: char) -> Option<Self> {
88        match c {
89            '2' => Some(Self::R2),
90            '3' => Some(Self::R3),
91            '4' => Some(Self::R4),
92            '5' => Some(Self::R5),
93            '6' => Some(Self::R6),
94            '7' => Some(Self::R7),
95            '8' => Some(Self::R8),
96            '9' => Some(Self::R9),
97            't' | 'T' => Some(Self::RT),
98            'j' | 'J' => Some(Self::RJ),
99            'q' | 'Q' => Some(Self::RQ),
100            'k' | 'K' => Some(Self::RK),
101            'a' | 'A' => Some(Self::RA),
102            _ => None,
103        }
104    }
105}
106
107impl From<Rank> for char {
108    fn from(value: Rank) -> Self {
109        match value {
110            Rank::R2 => '2',
111            Rank::R3 => '3',
112            Rank::R4 => '4',
113            Rank::R5 => '5',
114            Rank::R6 => '6',
115            Rank::R7 => '7',
116            Rank::R8 => '8',
117            Rank::R9 => '9',
118            Rank::RT => 'T',
119            Rank::RJ => 'J',
120            Rank::RQ => 'Q',
121            Rank::RK => 'K',
122            Rank::RA => 'A',
123        }
124    }
125}
126
127impl From<&Rank> for char {
128    fn from(r: &Rank) -> Self {
129        Self::from(*r)
130    }
131}
132
133impl TryFrom<char> for Rank {
134    type Error = ParseError;
135
136    fn try_from(c: char) -> Result<Self, Self::Error> {
137        match c {
138            '2' => Ok(Self::R2),
139            '3' => Ok(Self::R3),
140            '4' => Ok(Self::R4),
141            '5' => Ok(Self::R5),
142            '6' => Ok(Self::R6),
143            '7' => Ok(Self::R7),
144            '8' => Ok(Self::R8),
145            '9' => Ok(Self::R9),
146            'T' | 't' => Ok(Self::RT),
147            'J' | 'j' => Ok(Self::RJ),
148            'Q' | 'q' => Ok(Self::RQ),
149            'K' | 'k' => Ok(Self::RK),
150            'A' | 'a' => Ok(Self::RA),
151            _ => Err(ParseError::InvalidRank(c.into())),
152        }
153    }
154}
155
156impl FromStr for Rank {
157    type Err = ParseError;
158
159    fn from_str(s: &str) -> Result<Self, Self::Err> {
160        let mut cs = s.chars().filter(|c| !c.is_whitespace());
161        if let Some(c) = cs.next()
162            && let Ok(r) = Self::try_from(c)
163            && cs.next().is_none()
164        {
165            return Ok(r);
166        }
167        Err(ParseError::InvalidRank(s.into()))
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    impl Arbitrary for Rank {
176        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
177            *g.choose(&Self::ARR_ALL).unwrap()
178        }
179    }
180
181    #[test]
182    fn test_consts() {
183        assert_eq!(
184            Rank::ARR_ALL,
185            [
186                Rank::R2,
187                Rank::R3,
188                Rank::R4,
189                Rank::R5,
190                Rank::R6,
191                Rank::R7,
192                Rank::R8,
193                Rank::R9,
194                Rank::RT,
195                Rank::RJ,
196                Rank::RQ,
197                Rank::RK,
198                Rank::RA,
199            ]
200        );
201    }
202
203    #[test]
204    fn test_as_int() {
205        assert_eq!(Rank::R2 as i8, 0);
206        assert_eq!(Rank::R3 as i8, 1);
207        assert_eq!(Rank::R4 as i8, 2);
208        assert_eq!(Rank::R5 as i8, 3);
209        assert_eq!(Rank::R6 as i8, 4);
210        assert_eq!(Rank::R7 as i8, 5);
211        assert_eq!(Rank::R8 as i8, 6);
212        assert_eq!(Rank::R9 as i8, 7);
213        assert_eq!(Rank::RT as i8, 8);
214        assert_eq!(Rank::RJ as i8, 9);
215        assert_eq!(Rank::RQ as i8, 10);
216        assert_eq!(Rank::RK as i8, 11);
217        assert_eq!(Rank::RA as i8, 12);
218    }
219
220    #[test]
221    fn test_from_char() {
222        assert_eq!(Ok(Rank::R2), '2'.try_into());
223        assert_eq!(Ok(Rank::R3), '3'.try_into());
224        assert_eq!(Ok(Rank::R4), '4'.try_into());
225        assert_eq!(Ok(Rank::R5), '5'.try_into());
226        assert_eq!(Ok(Rank::R6), '6'.try_into());
227        assert_eq!(Ok(Rank::R7), '7'.try_into());
228        assert_eq!(Ok(Rank::R8), '8'.try_into());
229        assert_eq!(Ok(Rank::R9), '9'.try_into());
230
231        assert_eq!(Ok(Rank::RT), 'T'.try_into());
232        assert_eq!(Ok(Rank::RJ), 'J'.try_into());
233        assert_eq!(Ok(Rank::RQ), 'Q'.try_into());
234        assert_eq!(Ok(Rank::RK), 'K'.try_into());
235        assert_eq!(Ok(Rank::RA), 'A'.try_into());
236
237        assert_eq!(Ok(Rank::RT), 't'.try_into());
238        assert_eq!(Ok(Rank::RJ), 'j'.try_into());
239        assert_eq!(Ok(Rank::RQ), 'q'.try_into());
240        assert_eq!(Ok(Rank::RK), 'k'.try_into());
241        assert_eq!(Ok(Rank::RA), 'a'.try_into());
242
243        assert_eq!(
244            Err(ParseError::InvalidRank("?".into())),
245            Rank::try_from('?')
246        );
247    }
248
249    #[test]
250    fn test_from_char_option() {
251        assert_eq!(Some(Rank::R2), Rank::from_char('2'));
252        assert_eq!(Some(Rank::R3), Rank::from_char('3'));
253        assert_eq!(Some(Rank::R4), Rank::from_char('4'));
254        assert_eq!(Some(Rank::R5), Rank::from_char('5'));
255        assert_eq!(Some(Rank::R6), Rank::from_char('6'));
256        assert_eq!(Some(Rank::R7), Rank::from_char('7'));
257        assert_eq!(Some(Rank::R8), Rank::from_char('8'));
258        assert_eq!(Some(Rank::R9), Rank::from_char('9'));
259
260        assert_eq!(Some(Rank::RT), Rank::from_char('T'));
261        assert_eq!(Some(Rank::RJ), Rank::from_char('J'));
262        assert_eq!(Some(Rank::RQ), Rank::from_char('Q'));
263        assert_eq!(Some(Rank::RK), Rank::from_char('K'));
264        assert_eq!(Some(Rank::RA), Rank::from_char('A'));
265
266        assert_eq!(Some(Rank::RT), Rank::from_char('t'));
267        assert_eq!(Some(Rank::RJ), Rank::from_char('j'));
268        assert_eq!(Some(Rank::RQ), Rank::from_char('q'));
269        assert_eq!(Some(Rank::RK), Rank::from_char('k'));
270        assert_eq!(Some(Rank::RA), Rank::from_char('a'));
271
272        assert_eq!(None, Rank::from_char('?'));
273        assert_eq!(None, Rank::from_char('1'));
274        assert_eq!(None, Rank::from_char('X'));
275    }
276
277    #[test]
278    fn test_from_str() {
279        assert_eq!(Ok(Rank::R2), " 2 ".parse());
280        assert_eq!(
281            Err(ParseError::InvalidRank("23".into())),
282            "23".parse::<Rank>()
283        );
284        assert!("".parse::<Rank>().is_err());
285        assert!("?".parse::<Rank>().is_err());
286    }
287
288    #[test]
289    fn test_to_string() {
290        assert_eq!("2", &Rank::R2.to_string());
291        assert_eq!("3", &Rank::R3.to_string());
292        assert_eq!("4", &Rank::R4.to_string());
293        assert_eq!("5", &Rank::R5.to_string());
294        assert_eq!("6", &Rank::R6.to_string());
295        assert_eq!("7", &Rank::R7.to_string());
296        assert_eq!("8", &Rank::R8.to_string());
297        assert_eq!("9", &Rank::R9.to_string());
298        assert_eq!("T", &Rank::RT.to_string());
299        assert_eq!("J", &Rank::RJ.to_string());
300        assert_eq!("Q", &Rank::RQ.to_string());
301        assert_eq!("K", &Rank::RK.to_string());
302        assert_eq!("A", &Rank::RA.to_string());
303    }
304}