Skip to main content

server/domain/types/card/
suit.rs

1use serde::{Deserialize, Serialize};
2use strum::{AsRefStr, EnumIter};
3
4use crate::domain::CardsError;
5
6/// The four suits in a standard French playing card deck.
7#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, EnumIter, AsRefStr)]
8#[rustfmt::skip]
9pub enum Suit {
10    #[doc(hidden)] Hearts,
11    #[doc(hidden)] Clubs,
12    #[doc(hidden)] Diamonds,
13    #[doc(hidden)] Spades,
14}
15
16impl TryFrom<char> for Suit {
17    type Error = CardsError;
18
19    fn try_from(value: char) -> Result<Self, Self::Error> {
20        match value {
21            'H' => Ok(Self::Hearts),
22            'C' => Ok(Self::Clubs),
23            'D' => Ok(Self::Diamonds),
24            'S' => Ok(Self::Spades),
25            other => Err(CardsError::InvalidCard(format!("Invalid suit: {other}"))),
26        }
27    }
28}
29
30impl std::fmt::Display for Suit {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        let s = match self {
33            Self::Hearts => "H",
34            Self::Clubs => "C",
35            Self::Diamonds => "D",
36            Self::Spades => "S",
37        };
38        s.fmt(f)
39    }
40}
41
42#[cfg(test)]
43#[coverage(off)]
44pub mod test {
45    use super::*;
46
47    #[test]
48    fn suit_has_display_string() {
49        let suits = [
50            (Suit::Hearts, "H"),
51            (Suit::Clubs, "C"),
52            (Suit::Diamonds, "D"),
53            (Suit::Spades, "S"),
54        ];
55
56        for (suit, display_string) in suits {
57            assert_eq!(suit.to_string(), display_string);
58        }
59    }
60}