Skip to main content

tinystr/
unvalidated.rs

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
5use crate::ParseError;
6use crate::TinyAsciiStr;
7use 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(#[automatically_derived]
impl<const N : usize> ::core::cmp::PartialEq for UnvalidatedTinyAsciiStr<N> {
    #[inline]
    fn eq(&self, other: &UnvalidatedTinyAsciiStr<N>) -> bool {
        self.0 == other.0
    }
}PartialEq, #[automatically_derived]
impl<const N : usize> ::core::cmp::PartialOrd for UnvalidatedTinyAsciiStr<N> {
    #[inline]
    fn partial_cmp(&self, other: &UnvalidatedTinyAsciiStr<N>)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
    }
}PartialOrd, #[automatically_derived]
impl<const N : usize> ::core::cmp::Eq for UnvalidatedTinyAsciiStr<N> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<[u8; N]>;
    }
}Eq, #[automatically_derived]
impl<const N : usize> ::core::cmp::Ord for UnvalidatedTinyAsciiStr<N> {
    #[inline]
    fn cmp(&self, other: &UnvalidatedTinyAsciiStr<N>)
        -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
    }
}Ord, #[automatically_derived]
impl<const N : usize> ::core::clone::Clone for UnvalidatedTinyAsciiStr<N> {
    #[inline]
    fn clone(&self) -> UnvalidatedTinyAsciiStr<N> {
        let _: ::core::clone::AssertParamIsClone<[u8; N]>;
        *self
    }
}Clone, #[automatically_derived]
impl<const N : usize> ::core::marker::Copy for UnvalidatedTinyAsciiStr<N> { }Copy)]
17pub struct UnvalidatedTinyAsciiStr<const N: usize>(pub(crate) [u8; N]);
18
19impl<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) => fmt::Debug::fmt(&s, f),
24            Err(_) => fmt::Debug::fmt(&self.0, f),
25        }
26    }
27}
28
29impl<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>, ParseError> {
33        TinyAsciiStr::try_from_raw(self.0)
34    }
35
36    #[inline]
37    /// Creates one of these from a byte slice. Fails if the bytes are too long, but
38    /// does not check whether the bytes are a valid ASCII string.
39    pub fn try_from_utf8(bytes: &[u8]) -> Result<Self, ParseError> {
40        if bytes.len() > N {
41            return Err(ParseError::TooLong {
42                max: N,
43                len: bytes.len(),
44            });
45        }
46        let mut target = [0u8; N];
47        target[0..bytes.len()].copy_from_slice(bytes);
48        Ok(Self(target))
49    }
50
51    #[inline]
52    /// Creates one of these from a raw byte array.
53    pub const fn from_utf8_unchecked(bytes: [u8; N]) -> Self {
54        Self(bytes)
55    }
56}
57
58impl<const N: usize> TinyAsciiStr<N> {
59    #[inline]
60    // Converts into a [`UnvalidatedTinyAsciiStr`]
61    pub const fn to_unvalidated(self) -> UnvalidatedTinyAsciiStr<N> {
62        UnvalidatedTinyAsciiStr(*self.all_bytes())
63    }
64}
65
66impl<const N: usize> From<TinyAsciiStr<N>> for UnvalidatedTinyAsciiStr<N> {
67    fn from(other: TinyAsciiStr<N>) -> Self {
68        other.to_unvalidated()
69    }
70}
71
72#[cfg(feature = "serde")]
73impl<const N: usize> serde_core::Serialize for UnvalidatedTinyAsciiStr<N> {
74    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75    where
76        S: serde_core::Serializer,
77    {
78        use serde_core::ser::Error;
79        self.try_into_tinystr()
80            .map_err(|_| S::Error::custom("invalid ascii in UnvalidatedTinyAsciiStr"))?
81            .serialize(serializer)
82    }
83}
84
85macro_rules! deserialize {
86    ($size:literal) => {
87        #[cfg(feature = "serde")]
88        impl<'de, 'a> serde_core::Deserialize<'de> for UnvalidatedTinyAsciiStr<$size>
89        where
90            'de: 'a,
91        {
92            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
93            where
94                D: serde_core::Deserializer<'de>,
95            {
96                if deserializer.is_human_readable() {
97                    Ok(TinyAsciiStr::deserialize(deserializer)?.to_unvalidated())
98                } else {
99                    Ok(Self(<[u8; $size]>::deserialize(deserializer)?))
100                }
101            }
102        }
103    };
104}
105
106deserialize!(1);
107deserialize!(2);
108deserialize!(3);
109deserialize!(4);
110deserialize!(5);
111deserialize!(6);
112deserialize!(7);
113deserialize!(8);
114deserialize!(9);
115deserialize!(10);
116deserialize!(11);
117deserialize!(12);
118deserialize!(13);
119deserialize!(14);
120deserialize!(15);
121deserialize!(16);
122deserialize!(17);
123deserialize!(18);
124deserialize!(19);
125deserialize!(20);
126deserialize!(21);
127deserialize!(22);
128deserialize!(23);
129deserialize!(24);
130deserialize!(25);
131deserialize!(26);
132deserialize!(27);
133deserialize!(28);
134deserialize!(29);
135deserialize!(30);
136deserialize!(31);
137deserialize!(32);