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}