From 60728060a31939fe1b6fc977b4563ea8f2e896bd Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Sat, 30 May 2026 09:59:58 -0700 Subject: [PATCH] serde for Card, Stack, Pile --- Cargo.lock | 2 ++ card_game/Cargo.toml | 6 ++++++ card_game/src/lib.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 343cacc..f91f9e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,6 +25,8 @@ name = "card_game" version = "0.4.0" dependencies = [ "arrayvec", + "serde", + "serde_derive", ] [[package]] diff --git a/card_game/Cargo.toml b/card_game/Cargo.toml index 051d596..64feed5 100644 --- a/card_game/Cargo.toml +++ b/card_game/Cargo.toml @@ -10,6 +10,12 @@ keywords = ["card", "cards", "solitaire", "klondike"] [dependencies] arrayvec = { version = "0.7.6", registry = "Quaternions", features = ["len_u8"], default-features = false } +serde = { version = "1.0.228", default-features = false, optional = true } +serde_derive = { version = "1.0.228", default-features = false, optional = true } [lints] workspace = true + +[features] +default = ["serde"] +serde = ["dep:serde", "dep:serde_derive"] diff --git a/card_game/src/lib.rs b/card_game/src/lib.rs index ab698e0..70f16a0 100644 --- a/card_game/src/lib.rs +++ b/card_game/src/lib.rs @@ -146,6 +146,11 @@ impl Rank { /// 2 bits for suit ID /// 4 bits for card Value #[derive(Clone, Debug, Eq, Hash, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde_derive::Deserialize, serde_derive::Serialize), + serde(transparent) +)] pub struct Card(core::num::NonZeroU8); impl Card { pub const fn new(deck: Deck, suit: Suit, rank: Rank) -> Self { @@ -229,9 +234,54 @@ impl IntoIterator for Stack { self.0.into_iter() } } +#[cfg(feature = "serde")] +impl<'de, const CAP: usize> serde::Deserialize<'de> for Stack { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct StackVisitor; + impl<'de, const CAP: usize> serde::de::Visitor<'de> for StackVisitor { + type Value = Stack; + fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Card Stack") + } + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + let mut stack = Stack::new(); + while let Some(card) = seq.next_element()? { + // TODO: Error + stack.try_push(card).unwrap(); + } + Ok(stack) + } + } + deserializer.deserialize_seq(StackVisitor) + } +} +#[cfg(feature = "serde")] +impl serde::Serialize for Stack { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeSeq; + let mut seq = serializer.serialize_seq(Some(self.len()))?; + for card in self.as_slice() { + seq.serialize_element(card)?; + } + seq.end() + } +} /// A pile is a stack of face down cards and a stack of face up cards. #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(serde_derive::Deserialize, serde_derive::Serialize) +)] pub struct Pile { face_down: Stack, face_up: Stack,