icu_locale_core/extensions/transform/
key.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
5#[repr(transparent)]
#[doc = r" A key used in a list of [`Fields`](super::Fields)."]
#[doc = r""]
#[doc = r" The key has to be a two ASCII characters long, with the first"]
#[doc = r" character being alphabetic, and the second being a number."]
#[doc = r""]
#[doc = r" # Examples"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" use icu::locale::extensions::transform::Key;"]
#[doc = r""]
#[doc = r#" let key1: Key = "k0".parse().expect("Failed to parse a Key.");"#]
#[doc = r""]
#[doc = r#" assert_eq!(key1.as_str(), "k0");"#]
#[doc = r" ```"]
pub struct Key(tinystr::TinyAsciiStr<2>);
#[automatically_derived]
impl ::core::fmt::Debug for Key {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Key", &&self.0)
    }
}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Key { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Key {
    #[inline]
    fn eq(&self, other: &Key) -> bool { self.0 == other.0 }
}
#[automatically_derived]
impl ::core::cmp::Eq for Key {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<tinystr::TinyAsciiStr<2>>;
    }
}
#[automatically_derived]
impl ::core::clone::Clone for Key {
    #[inline]
    fn clone(&self) -> Key {
        let _: ::core::clone::AssertParamIsClone<tinystr::TinyAsciiStr<2>>;
        *self
    }
}
#[automatically_derived]
impl ::core::hash::Hash for Key {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.0, state)
    }
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Key {
    #[inline]
    fn partial_cmp(&self, other: &Key)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
    }
}
#[automatically_derived]
impl ::core::cmp::Ord for Key {
    #[inline]
    fn cmp(&self, other: &Key) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
    }
}
#[automatically_derived]
impl ::core::marker::Copy for Key { }
impl Key {
    /// A constructor which takes a str slice, parses it and
    #[doc = "produces a well-formed [`Key`]."]
    ///
    /// # Examples
    ///
    /// ```
    #[doc = "use icu_locale_core::extensions :: transform ::Key;"]
    ///
    #[doc = "assert!(Key::try_from_str(\"k0\").is_ok());"]
    #[doc = "assert!(Key::try_from_str(\"\").is_err());"]
    /// ```
    #[inline]
    pub const fn try_from_str(s: &str)
        -> Result<Self, crate::parser::errors::ParseError> {
        Self::try_from_utf8(s.as_bytes())
    }
    /// See [`Self::try_from_str`]
    pub const fn try_from_utf8(code_units: &[u8])
        -> Result<Self, crate::parser::errors::ParseError> {

        #[allow(clippy :: double_comparisons)]
        if code_units.len() < 2 || code_units.len() > 2 {
            return Err(crate::parser::errors::ParseError::InvalidExtension);
        }
        match tinystr::TinyAsciiStr::try_from_utf8(code_units) {
            Ok(s) if
                s.all_bytes()[0].is_ascii_alphabetic() &&
                    s.all_bytes()[1].is_ascii_digit() =>
                Ok(Self(s.to_ascii_lowercase())),
            _ => Err(crate::parser::errors::ParseError::InvalidExtension),
        }
    }
    #[doc = "Safely creates a [`Key`] from its raw format"]
    /// as returned by [`Self::into_raw`]. Unlike [`Self::try_from_utf8`],
    /// this constructor only takes normalized values.
    pub const fn try_from_raw(raw: [u8; 2])
        -> Result<Self, crate::parser::errors::ParseError> {
        if let Ok(s) = tinystr::TinyAsciiStr::<2>::try_from_raw(raw) {
            if s.len() >= 2 &&
                    (s.all_bytes()[0].is_ascii_lowercase() &&
                        s.all_bytes()[1].is_ascii_digit()) {
                Ok(Self(s))
            } else {
                Err(crate::parser::errors::ParseError::InvalidExtension)
            }
        } else { Err(crate::parser::errors::ParseError::InvalidExtension) }
    }
    #[doc = "Unsafely creates a [`Key`] from its raw format"]
    /// as returned by [`Self::into_raw`]. Unlike [`Self::try_from_utf8`],
    /// this constructor only takes normalized values.
    ///
    /// # Safety
    ///
    /// This function is safe iff [`Self::try_from_raw`] returns an `Ok`. This is the case
    /// for inputs that are correctly normalized.
    pub const unsafe fn from_raw_unchecked(v: [u8; 2]) -> Self {
        Self(tinystr::TinyAsciiStr::from_utf8_unchecked(v))
    }
    /// Deconstructs into a raw format to be consumed by
    /// [`from_raw_unchecked`](Self::from_raw_unchecked()) or
    /// [`try_from_raw`](Self::try_from_raw()).
    pub const fn into_raw(self) -> [u8; 2] { *self.0.all_bytes() }
    #[inline]
    /// A helper function for displaying as a `&str`.
    pub const fn as_str(&self) -> &str { self.0.as_str() }
    #[doc(hidden)]
    pub const fn to_tinystr(&self) -> tinystr::TinyAsciiStr<2> { self.0 }
    /// Compare with BCP-47 bytes.
    ///
    /// The return value is equivalent to what would happen if you first converted
    /// `self` to a BCP-47 string and then performed a byte comparison.
    ///
    /// This function is case-sensitive and results in a *total order*, so it is appropriate for
    /// binary search. The only argument producing [`Ordering::Equal`](core::cmp::Ordering::Equal)
    /// is `self.as_str().as_bytes()`.
    #[inline]
    pub fn strict_cmp(self, other: &[u8]) -> core::cmp::Ordering {
        self.as_str().as_bytes().cmp(other)
    }
    /// Compare with a potentially unnormalized BCP-47 string.
    ///
    /// The return value is equivalent to what would happen if you first parsed the
    /// BCP-47 string and then performed a structural comparison.
    ///
    #[inline]
    pub fn normalizing_eq(self, other: &str) -> bool {
        self.as_str().eq_ignore_ascii_case(other)
    }
}
impl core::str::FromStr for Key {
    type Err = crate::parser::errors::ParseError;
    #[inline]
    fn from_str(s: &str) -> Result<Self, Self::Err> { Self::try_from_str(s) }
}
impl<'l> From<&'l Key> for &'l str {
    fn from(input: &'l Key) -> Self { input.as_str() }
}
impl From<Key> for tinystr::TinyAsciiStr<2> {
    fn from(input: Key) -> Self { input.to_tinystr() }
}
impl writeable::Writeable for Key {
    #[inline]
    fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W)
        -> core::fmt::Result {
        sink.write_str(self.as_str())
    }
    #[inline]
    fn writeable_length_hint(&self) -> writeable::LengthHint {
        writeable::LengthHint::exact(self.0.len())
    }
}
/// This trait is implemented for compatibility with [`fmt!`](alloc::fmt).
/// To create a string, [`Writeable::write_to_string`] is usually more efficient.
impl core::fmt::Display for Key {
    #[inline]
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        ::writeable::Writeable::write_to(&self, f)
    }
}
impl Key {
    /// Converts the given value to a `String`.
    ///
    /// Under the hood, this uses an efficient [`Writeable`] implementation.
    /// However, in order to avoid allocating a string, it is more efficient
    /// to use [`Writeable`] directly.
    pub fn to_string(&self) -> ::writeable::_internal::String {
        ::writeable::Writeable::write_to_string(self).into_owned()
    }
}
#[doc =
"A macro allowing for compile-time construction of valid [`Key`] subtags."]
///
/// # Examples
///
/// Parsing errors don't have to be handled at runtime:
/// ```
/// assert_eq!(
#[doc = "  icu_locale_core::extensions::transform::key!(\"k0\"),"]
#[doc =
"  \"k0\".parse::<icu_locale_core::extensions::transform::Key>().unwrap()"]
/// );
/// ```
///
/// Invalid input is a compile failure:
/// ```compile_fail,E0080
#[doc = "icu_locale_core::extensions::transform::key!(\"\");"]
/// ```
///
#[doc = "[`Key`]: crate::extensions::transform::Key"]
#[macro_export]
#[doc(hidden)]
macro_rules! extensions_transform_key {
    ($string : literal) =>
    {
        const
        {
            use crate :: extensions :: transform :: Key; match Key ::
            try_from_utf8($string.as_bytes())
            {
                Ok(r) => r, #[allow(clippy :: panic)] _ => panic!
                (concat!
                ("Invalid ", stringify! (extensions), "::", stringify!
                (transform), "::", stringify! (Key), ": ", $string)),
            }
        }
    };
}
#[doc(inline)]
pub use extensions_transform_key as key;
unsafe impl zerovec::ule::ULE for Key {
    fn validate_bytes(bytes: &[u8]) -> Result<(), zerovec::ule::UleError> {
        let it = bytes.chunks_exact(core::mem::size_of::<Self>());
        if !it.remainder().is_empty() {
            return Err(zerovec::ule::UleError::length::<Self>(bytes.len()));
        }
        for v in it {
            let mut a = [0; core::mem::size_of::<Self>()];
            a.copy_from_slice(v);
            if Self::try_from_raw(a).is_err() {
                return Err(zerovec::ule::UleError::parse::<Self>());
            }
        }
        Ok(())
    }
}
impl zerovec::ule::NicheBytes<2> for Key {
    const NICHE_BIT_PATTERN: [u8; 2] =
        <tinystr::TinyAsciiStr<2>>::NICHE_BIT_PATTERN;
}
impl zerovec::ule::AsULE for Key {
    type ULE = Self;
    fn to_unaligned(self) -> Self::ULE { self }
    fn from_unaligned(unaligned: Self::ULE) -> Self { unaligned }
}
impl<'a> zerovec::maps::ZeroMapKV<'a> for Key {
    type Container = zerovec::ZeroVec<'a, Key>;
    type Slice = zerovec::ZeroSlice<Key>;
    type GetType = Key;
    type OwnedType = Key;
}impl_tinystr_subtag!(
6    /// A key used in a list of [`Fields`](super::Fields).
7    ///
8    /// The key has to be a two ASCII characters long, with the first
9    /// character being alphabetic, and the second being a number.
10    ///
11    /// # Examples
12    ///
13    /// ```
14    /// use icu::locale::extensions::transform::Key;
15    ///
16    /// let key1: Key = "k0".parse().expect("Failed to parse a Key.");
17    ///
18    /// assert_eq!(key1.as_str(), "k0");
19    /// ```
20    Key,
21    extensions::transform,
22    key,
23    extensions_transform_key,
24    2..=2,
25    s,
26    s.all_bytes()[0].is_ascii_alphabetic() && s.all_bytes()[1].is_ascii_digit(),
27    s.to_ascii_lowercase(),
28    s.all_bytes()[0].is_ascii_lowercase() && s.all_bytes()[1].is_ascii_digit(),
29    InvalidExtension,
30    ["k0"],
31    ["", "k", "0k", "k12"],
32);