| 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::TinyAsciiStr; |
| 6 | use crate::TinyStrError; |
| 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> { |
| 20 | 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: TinyAsciiStr) => 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. |
| 32 | pub fn try_into_tinystr(&self) -> Result<TinyAsciiStr<N>, TinyStrError> { |
| 33 | TinyAsciiStr::try_from_raw(self.0) |
| 34 | } |
| 35 | |
| 36 | #[doc (hidden)] |
| 37 | pub const fn from_bytes_unchecked(bytes: [u8; N]) -> Self { |
| 38 | Self(bytes) |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | impl<const N: usize> TinyAsciiStr<N> { |
| 43 | #[inline ] |
| 44 | // Converts into a [`UnvalidatedTinyAsciiStr`] |
| 45 | pub const fn to_unvalidated(self) -> UnvalidatedTinyAsciiStr<N> { |
| 46 | UnvalidatedTinyAsciiStr(*self.all_bytes()) |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | impl<const N: usize> From<TinyAsciiStr<N>> for UnvalidatedTinyAsciiStr<N> { |
| 51 | fn from(other: TinyAsciiStr<N>) -> Self { |
| 52 | other.to_unvalidated() |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | #[cfg (feature = "serde" )] |
| 57 | impl<const N: usize> serde::Serialize for UnvalidatedTinyAsciiStr<N> { |
| 58 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| 59 | where |
| 60 | S: serde::Serializer, |
| 61 | { |
| 62 | use serde::ser::Error; |
| 63 | self.try_into_tinystr() |
| 64 | .map_err(|_| S::Error::custom("invalid ascii in UnvalidatedTinyAsciiStr" ))? |
| 65 | .serialize(serializer) |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | macro_rules! deserialize { |
| 70 | ($size:literal) => { |
| 71 | #[cfg(feature = "serde" )] |
| 72 | impl<'de, 'a> serde::Deserialize<'de> for UnvalidatedTinyAsciiStr<$size> |
| 73 | where |
| 74 | 'de: 'a, |
| 75 | { |
| 76 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| 77 | where |
| 78 | D: serde::Deserializer<'de>, |
| 79 | { |
| 80 | if deserializer.is_human_readable() { |
| 81 | Ok(TinyAsciiStr::deserialize(deserializer)?.to_unvalidated()) |
| 82 | } else { |
| 83 | Ok(Self(<[u8; $size]>::deserialize(deserializer)?)) |
| 84 | } |
| 85 | } |
| 86 | } |
| 87 | }; |
| 88 | } |
| 89 | |
| 90 | deserialize!(1); |
| 91 | deserialize!(2); |
| 92 | deserialize!(3); |
| 93 | deserialize!(4); |
| 94 | deserialize!(5); |
| 95 | deserialize!(6); |
| 96 | deserialize!(7); |
| 97 | deserialize!(8); |
| 98 | deserialize!(9); |
| 99 | deserialize!(10); |
| 100 | deserialize!(11); |
| 101 | deserialize!(12); |
| 102 | deserialize!(13); |
| 103 | deserialize!(14); |
| 104 | deserialize!(15); |
| 105 | deserialize!(16); |
| 106 | deserialize!(17); |
| 107 | deserialize!(18); |
| 108 | deserialize!(19); |
| 109 | deserialize!(20); |
| 110 | deserialize!(21); |
| 111 | deserialize!(22); |
| 112 | deserialize!(23); |
| 113 | deserialize!(24); |
| 114 | deserialize!(25); |
| 115 | deserialize!(26); |
| 116 | deserialize!(27); |
| 117 | deserialize!(28); |
| 118 | deserialize!(29); |
| 119 | deserialize!(30); |
| 120 | deserialize!(31); |
| 121 | deserialize!(32); |
| 122 | |