| // 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 crate::TinyStrError; |
| use core::fmt; |
| |
| /// A fixed-length bytes array that is expected to be an ASCII string but does not enforce that invariant. |
| /// |
| /// Use this type instead of `TinyAsciiStr` if you don't need to enforce ASCII during deserialization. For |
| /// example, strings that are keys of a map don't need to ever be reified as `TinyAsciiStr`s. |
| /// |
| /// The main advantage of this type over `[u8; N]` is that it serializes as a string in |
| /// human-readable formats like JSON. |
| #[derive(PartialEq, PartialOrd, Eq, Ord, Clone, Copy)] |
| pub struct UnvalidatedTinyAsciiStr<const N: usize>(pub(crate) [u8; N]); |
| |
| impl<const N: usize> fmt::Debug for UnvalidatedTinyAsciiStr<N> { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| // Debug as a string if possible |
| match self.try_into_tinystr() { |
| Ok(s) => fmt::Debug::fmt(&s, f), |
| Err(_) => fmt::Debug::fmt(&self.0, f), |
| } |
| } |
| } |
| |
| impl<const N: usize> UnvalidatedTinyAsciiStr<N> { |
| #[inline] |
| // Converts into a [`TinyAsciiStr`]. Fails if the bytes are not valid ASCII. |
| pub fn try_into_tinystr(&self) -> Result<TinyAsciiStr<N>, TinyStrError> { |
| TinyAsciiStr::try_from_raw(self.0) |
| } |
| |
| #[doc(hidden)] |
| pub const fn from_bytes_unchecked(bytes: [u8; N]) -> Self { |
| Self(bytes) |
| } |
| } |
| |
| impl<const N: usize> TinyAsciiStr<N> { |
| #[inline] |
| // Converts into a [`UnvalidatedTinyAsciiStr`] |
| pub const fn to_unvalidated(self) -> UnvalidatedTinyAsciiStr<N> { |
| UnvalidatedTinyAsciiStr(*self.all_bytes()) |
| } |
| } |
| |
| impl<const N: usize> From<TinyAsciiStr<N>> for UnvalidatedTinyAsciiStr<N> { |
| fn from(other: TinyAsciiStr<N>) -> Self { |
| other.to_unvalidated() |
| } |
| } |
| |
| #[cfg(feature = "serde")] |
| impl<const N: usize> serde::Serialize for UnvalidatedTinyAsciiStr<N> { |
| fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| where |
| S: serde::Serializer, |
| { |
| use serde::ser::Error; |
| self.try_into_tinystr() |
| .map_err(|_| S::Error::custom("invalid ascii in UnvalidatedTinyAsciiStr"))? |
| .serialize(serializer) |
| } |
| } |
| |
| macro_rules! deserialize { |
| ($size:literal) => { |
| #[cfg(feature = "serde")] |
| impl<'de, 'a> serde::Deserialize<'de> for UnvalidatedTinyAsciiStr<$size> |
| where |
| 'de: 'a, |
| { |
| fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| where |
| D: serde::Deserializer<'de>, |
| { |
| if deserializer.is_human_readable() { |
| Ok(TinyAsciiStr::deserialize(deserializer)?.to_unvalidated()) |
| } else { |
| Ok(Self(<[u8; $size]>::deserialize(deserializer)?)) |
| } |
| } |
| } |
| }; |
| } |
| |
| deserialize!(1); |
| deserialize!(2); |
| deserialize!(3); |
| deserialize!(4); |
| deserialize!(5); |
| deserialize!(6); |
| deserialize!(7); |
| deserialize!(8); |
| deserialize!(9); |
| deserialize!(10); |
| deserialize!(11); |
| deserialize!(12); |
| deserialize!(13); |
| deserialize!(14); |
| deserialize!(15); |
| deserialize!(16); |
| deserialize!(17); |
| deserialize!(18); |
| deserialize!(19); |
| deserialize!(20); |
| deserialize!(21); |
| deserialize!(22); |
| deserialize!(23); |
| deserialize!(24); |
| deserialize!(25); |
| deserialize!(26); |
| deserialize!(27); |
| deserialize!(28); |
| deserialize!(29); |
| deserialize!(30); |
| deserialize!(31); |
| deserialize!(32); |