1use super::*;
2
3#[derive(
5 Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Display, Default,
6)]
7pub enum Rank {
8 #[default]
10 #[display("2")]
11 R2 = 0,
12 #[display("3")]
14 R3,
15 #[display("4")]
17 R4,
18 #[display("5")]
20 R5,
21 #[display("6")]
23 R6,
24 #[display("7")]
26 R7,
27 #[display("8")]
29 R8,
30 #[display("9")]
32 R9,
33 #[display("T")]
35 RT,
36 #[display("J")]
38 RJ,
39 #[display("Q")]
41 RQ,
42 #[display("K")]
44 RK,
45 #[display("A")]
47 RA,
48}
49
50impl Rank {
51 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 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 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}