jevsnes.git / third-party / rust / jgenesis / config / nes-config / src / serialization.rs
1//! Code to make NES palettes serialize as a base64 string rather than raw bytes, so that they
2//! serialize nicer in TOML and other string-based config formats
3
4use crate::NesPalette;
5use base64::Engine;
6use serde::de::{Error, Visitor};
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use std::array;
9use std::fmt::Formatter;
10
11const BASE64_ENCODER: base64::engine::GeneralPurpose =
12    base64::engine::general_purpose::STANDARD_NO_PAD;
13
14impl Serialize for NesPalette {
15    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
16    where
17        S: Serializer,
18    {
19        let mut bytes = [0_u8; 512 * 3];
20        for (i, [r, g, b]) in bytes.as_chunks_mut::<3>().0.iter_mut().enumerate() {
21            (*r, *g, *b) = self.0[i];
22        }
23
24        let s = BASE64_ENCODER.encode(bytes);
25        serializer.serialize_str(&s)
26    }
27}
28
29struct DeserializeVisitor;
30
31impl Visitor<'_> for DeserializeVisitor {
32    type Value = NesPalette;
33
34    fn expecting(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
35        write!(formatter, "NES palette as a hex string")
36    }
37
38    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
39    where
40        E: Error,
41    {
42        let bytes =
43            BASE64_ENCODER.decode(v.as_bytes()).map_err(|err| Error::custom(err.to_string()))?;
44
45        if bytes.len() != 512 * 3 {
46            return Err(Error::custom(format!(
47                "Expected palette of length {}, was {}",
48                512 * 3,
49                bytes.len()
50            )));
51        }
52
53        Ok(NesPalette(array::from_fn(|i| (bytes[3 * i], bytes[3 * i + 1], bytes[3 * i + 2]))))
54    }
55}
56
57impl<'de> Deserialize<'de> for NesPalette {
58    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
59    where
60        D: Deserializer<'de>,
61    {
62        deserializer.deserialize_str(DeserializeVisitor)
63    }
64}