// This file is part of ICU4X. For terms of use, please see the file // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::TinyAsciiStr; use alloc::borrow::Cow; use alloc::string::ToString; use core::fmt; use core::marker::PhantomData; use core::ops::Deref; use serde::de::{Error, SeqAccess, Visitor}; use serde::ser::SerializeTuple; use serde::{Deserialize, Deserializer, Serialize, Serializer}; impl Serialize for TinyAsciiStr { #[inline] fn serialize(&self, serializer: S) -> Result where S: Serializer, { if serializer.is_human_readable() { self.deref().serialize(serializer) } else { let mut seq = serializer.serialize_tuple(N)?; for byte in self.all_bytes() { seq.serialize_element(byte)?; } seq.end() } } } struct TinyAsciiStrVisitor { marker: PhantomData>, } impl TinyAsciiStrVisitor { fn new() -> Self { TinyAsciiStrVisitor { marker: PhantomData, } } } impl<'de, const N: usize> Visitor<'de> for TinyAsciiStrVisitor { type Value = TinyAsciiStr; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "a TinyAsciiStr<{}>", N) } #[inline] fn visit_seq(self, mut seq: A) -> Result where A: SeqAccess<'de>, { let mut bytes = [0u8; N]; let mut zeroes = false; for out in &mut bytes.iter_mut().take(N) { let byte = seq .next_element()? .ok_or_else(|| Error::invalid_length(N, &self))?; if byte == 0 { zeroes = true; } else if zeroes { return Err(Error::custom("TinyAsciiStr cannot contain null bytes")); } if byte >= 0x80 { return Err(Error::custom("TinyAsciiStr cannot contain non-ascii bytes")); } *out = byte; } Ok(unsafe { TinyAsciiStr::from_bytes_unchecked(bytes) }) } } impl<'de, const N: usize> Deserialize<'de> for TinyAsciiStr { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { let x: Cow<'de, str> = Deserialize::deserialize(deserializer)?; TinyAsciiStr::from_str(&x).map_err(|e| Error::custom(e.to_string())) } else { deserializer.deserialize_tuple(N, TinyAsciiStrVisitor::::new()) } } }