openpql_prelude/card/
suit.rs1use super::{CardCount, Display, FromStr, Hash, Idx, ParseError};
2
3#[derive(
8 Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Display, Default,
9)]
10pub enum Suit {
11 #[display("s")]
12 #[default]
13 S = 0,
14 #[display("h")]
15 H,
16 #[display("d")]
17 D,
18 #[display("c")]
19 C,
20}
21
22impl Suit {
23 pub const N_SUITS: CardCount = 4;
25
26 pub const ARR_ALL: [Self; Self::N_SUITS as usize] =
28 [Self::S, Self::H, Self::D, Self::C];
29
30 pub const CHARS: [char; Self::N_SUITS as usize] = ['s', 'h', 'd', 'c'];
32 #[inline]
34 pub const fn from_char(c: char) -> Option<Self> {
35 match c {
36 'S' | 's' => Some(Self::S),
37 'H' | 'h' => Some(Self::H),
38 'D' | 'd' => Some(Self::D),
39 'C' | 'c' => Some(Self::C),
40 _ => None,
41 }
42 }
43
44 #[inline]
45 pub const fn to_char(self) -> char {
46 Self::CHARS[self as usize]
47 }
48
49 #[inline]
50 pub(crate) const fn eq(self, other: Self) -> bool {
51 self as Idx == other as Idx
52 }
53}
54
55impl TryFrom<char> for Suit {
56 type Error = ParseError;
57
58 fn try_from(c: char) -> Result<Self, Self::Error> {
59 Self::from_char(c).ok_or_else(|| ParseError::InvalidSuit(c.into()))
60 }
61}
62
63impl FromStr for Suit {
64 type Err = ParseError;
65
66 fn from_str(s: &str) -> Result<Self, Self::Err> {
67 let mut cs = s.chars().filter(|c| !c.is_whitespace());
68 if let Some(c) = cs.next()
69 && let Ok(s) = Self::try_from(c)
70 && cs.next().is_none()
71 {
72 return Ok(s);
73 }
74 Err(ParseError::InvalidSuit(s.into()))
75 }
76}
77
78#[cfg(any(test, feature = "quickcheck"))]
79impl quickcheck::Arbitrary for Suit {
80 fn arbitrary(g: &mut quickcheck::Gen) -> Self {
81 *g.choose(&Self::ARR_ALL).unwrap()
82 }
83}
84
85#[cfg(test)]
86#[cfg_attr(coverage_nightly, coverage(off))]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_all() {
92 assert_eq!(Suit::ARR_ALL, [Suit::S, Suit::H, Suit::D, Suit::C]);
93 }
94
95 #[test]
96 fn test_as_int() {
97 assert_eq!(Suit::S as Idx, 0);
98 assert_eq!(Suit::H as Idx, 1);
99 assert_eq!(Suit::D as Idx, 2);
100 assert_eq!(Suit::C as Idx, 3);
101 }
102
103 #[test]
104 fn test_from_char() {
105 assert_eq!('s'.try_into(), Ok(Suit::S));
106 assert_eq!('h'.try_into(), Ok(Suit::H));
107 assert_eq!('d'.try_into(), Ok(Suit::D));
108 assert_eq!('c'.try_into(), Ok(Suit::C));
109
110 assert_eq!('S'.try_into(), Ok(Suit::S));
111 assert_eq!('H'.try_into(), Ok(Suit::H));
112 assert_eq!('D'.try_into(), Ok(Suit::D));
113 assert_eq!('C'.try_into(), Ok(Suit::C));
114
115 assert_eq!(
116 Suit::try_from('?'),
117 Err(ParseError::InvalidSuit("?".into())),
118 );
119 }
120
121 #[test]
122 fn test_from_str() {
123 assert_eq!(" s ".parse(), Ok(Suit::S));
124 assert_eq!(
125 "sS".parse::<Suit>(),
126 Err(ParseError::InvalidSuit("sS".into())),
127 );
128 assert!("".parse::<Suit>().is_err());
129 assert!("?".parse::<Suit>().is_err());
130 }
131
132 #[test]
133 fn test_to_string() {
134 assert_eq!(&Suit::S.to_string(), "s");
135 assert_eq!(&Suit::H.to_string(), "h");
136 assert_eq!(&Suit::D.to_string(), "d");
137 assert_eq!(&Suit::C.to_string(), "c");
138 }
139
140 #[test]
141 fn test_to_char() {
142 assert_eq!(Suit::S.to_char(), 's');
143 assert_eq!(Suit::H.to_char(), 'h');
144 assert_eq!(Suit::D.to_char(), 'd');
145 assert_eq!(Suit::C.to_char(), 'c');
146 }
147}