1 // This file is part of ICU4X. For terms of use, please see the file 2 // called LICENSE at the top level of the ICU4X source tree 3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). 4 5 use crate::ParseError; 6 use crate::TinyAsciiStr; 7 use core::fmt; 8 9 /// A fixed-length bytes array that is expected to be an ASCII string but does not enforce that invariant. 10 /// 11 /// Use this type instead of `TinyAsciiStr` if you don't need to enforce ASCII during deserialization. For 12 /// example, strings that are keys of a map don't need to ever be reified as `TinyAsciiStr`s. 13 /// 14 /// The main advantage of this type over `[u8; N]` is that it serializes as a string in 15 /// human-readable formats like JSON. 16 #[derive(PartialEq, PartialOrd, Eq, Ord, Clone, Copy)] 17 pub struct UnvalidatedTinyAsciiStr<const N: usize>(pub(crate) [u8; N]); 18 19 impl<const N: usize> fmt::Debug for UnvalidatedTinyAsciiStr<N> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 21 // Debug as a string if possible 22 match self.try_into_tinystr() { 23 Ok(s) => fmt::Debug::fmt(&s, f), 24 Err(_) => fmt::Debug::fmt(&self.0, f), 25 } 26 } 27 } 28 29 impl<const N: usize> UnvalidatedTinyAsciiStr<N> { 30 #[inline] 31 /// Converts into a [`TinyAsciiStr`]. Fails if the bytes are not valid ASCII. try_into_tinystr(self) -> Result<TinyAsciiStr<N>, ParseError>32 pub fn try_into_tinystr(self) -> Result<TinyAsciiStr<N>, ParseError> { 33 TinyAsciiStr::try_from_raw(self.0) 34 } 35 36 #[inline] 37 /// Unsafely converts into a [`TinyAsciiStr`]. from_utf8_unchecked(bytes: [u8; N]) -> Self38 pub const fn from_utf8_unchecked(bytes: [u8; N]) -> Self { 39 Self(bytes) 40 } 41 } 42 43 impl<const N: usize> TinyAsciiStr<N> { 44 #[inline] 45 // Converts into a [`UnvalidatedTinyAsciiStr`] to_unvalidated(self) -> UnvalidatedTinyAsciiStr<N>46 pub const fn to_unvalidated(self) -> UnvalidatedTinyAsciiStr<N> { 47 UnvalidatedTinyAsciiStr(*self.all_bytes()) 48 } 49 } 50 51 impl<const N: usize> From<TinyAsciiStr<N>> for UnvalidatedTinyAsciiStr<N> { from(other: TinyAsciiStr<N>) -> Self52 fn from(other: TinyAsciiStr<N>) -> Self { 53 other.to_unvalidated() 54 } 55 } 56 57 #[cfg(feature = "serde")] 58 impl<const N: usize> serde::Serialize for UnvalidatedTinyAsciiStr<N> { serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer,59 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 60 where 61 S: serde::Serializer, 62 { 63 use serde::ser::Error; 64 self.try_into_tinystr() 65 .map_err(|_| S::Error::custom("invalid ascii in UnvalidatedTinyAsciiStr"))? 66 .serialize(serializer) 67 } 68 } 69 70 macro_rules! deserialize { 71 ($size:literal) => { 72 #[cfg(feature = "serde")] 73 impl<'de, 'a> serde::Deserialize<'de> for UnvalidatedTinyAsciiStr<$size> 74 where 75 'de: 'a, 76 { 77 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 78 where 79 D: serde::Deserializer<'de>, 80 { 81 if deserializer.is_human_readable() { 82 Ok(TinyAsciiStr::deserialize(deserializer)?.to_unvalidated()) 83 } else { 84 Ok(Self(<[u8; $size]>::deserialize(deserializer)?)) 85 } 86 } 87 } 88 }; 89 } 90 91 deserialize!(1); 92 deserialize!(2); 93 deserialize!(3); 94 deserialize!(4); 95 deserialize!(5); 96 deserialize!(6); 97 deserialize!(7); 98 deserialize!(8); 99 deserialize!(9); 100 deserialize!(10); 101 deserialize!(11); 102 deserialize!(12); 103 deserialize!(13); 104 deserialize!(14); 105 deserialize!(15); 106 deserialize!(16); 107 deserialize!(17); 108 deserialize!(18); 109 deserialize!(19); 110 deserialize!(20); 111 deserialize!(21); 112 deserialize!(22); 113 deserialize!(23); 114 deserialize!(24); 115 deserialize!(25); 116 deserialize!(26); 117 deserialize!(27); 118 deserialize!(28); 119 deserialize!(29); 120 deserialize!(30); 121 deserialize!(31); 122 deserialize!(32); 123