icu_locale_core/extensions/unicode/
attribute.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" An attribute used in a set of [`Attributes`](super::Attributes)."]
#[doc = r""]
#[doc = r" An attribute has to be a sequence of alphanumerical characters no"]
#[doc = r" shorter than three and no longer than eight characters."]
#[doc = r""]
#[doc = r""]
#[doc = r" # Examples"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" use icu::locale::extensions::unicode::{attribute, Attribute};"]
#[doc = r""]
#[doc = r" let attr: Attribute ="]
#[doc = r#"     "buddhist".parse().expect("Failed to parse an Attribute.");"#]
#[doc = r""]
#[doc = r#" assert_eq!(attr, attribute!("buddhist"));"#]
#[doc = r" ```"]
pub struct Attribute(tinystr::TinyAsciiStr<8>);
#[automatically_derived]
impl ::core::fmt::Debug for Attribute {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Attribute",
            &&self.0)
    }
}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Attribute { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Attribute {
    #[inline]
    fn eq(&self, other: &Attribute) -> bool { self.0 == other.0 }
}
#[automatically_derived]
impl ::core::cmp::Eq for Attribute {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<tinystr::TinyAsciiStr<8>>;
    }
}
#[automatically_derived]
impl ::core::clone::Clone for Attribute {
    #[inline]
    fn clone(&self) -> Attribute {
        let _: ::core::clone::AssertParamIsClone<tinystr::TinyAsciiStr<8>>;
        *self
    }
}
#[automatically_derived]
impl ::core::hash::Hash for Attribute {
    #[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 Attribute {
    #[inline]
    fn partial_cmp(&self, other: &Attribute)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
    }
}
#[automatically_derived]
impl ::core::cmp::Ord for Attribute {
    #[inline]
    fn cmp(&self, other: &Attribute) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
    }
}
#[automatically_derived]
impl ::core::marker::Copy for Attribute { }
impl Attribute {
    /// A constructor which takes a str slice, parses it and
    #[doc = "produces a well-formed [`Attribute`]."]
    ///
    /// # Examples
    ///
    /// ```
    #[doc = "use icu_locale_core::extensions :: unicode ::Attribute;"]
    ///
    #[doc = "assert!(Attribute::try_from_str(\"foo12\").is_ok());"]
    #[doc = "assert!(Attribute::try_from_str(\"no\").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() < 3 || code_units.len() > 8 {
            return Err(crate::parser::errors::ParseError::InvalidExtension);
        }
        match tinystr::TinyAsciiStr::try_from_utf8(code_units) {
            Ok(s) if s.is_ascii_alphanumeric() =>
                Ok(Self(s.to_ascii_lowercase())),
            _ => Err(crate::parser::errors::ParseError::InvalidExtension),
        }
    }
    #[doc = "Safely creates a [`Attribute`] 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; 8])
        -> Result<Self, crate::parser::errors::ParseError> {
        if let Ok(s) = tinystr::TinyAsciiStr::<8>::try_from_raw(raw) {
            if s.len() >= 3 &&
                    (s.is_ascii_alphanumeric() && s.is_ascii_lowercase()) {
                Ok(Self(s))
            } else {
                Err(crate::parser::errors::ParseError::InvalidExtension)
            }
        } else { Err(crate::parser::errors::ParseError::InvalidExtension) }
    }
    #[doc = "Unsafely creates a [`Attribute`] 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; 8]) -> 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; 8] { *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<8> { 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 Attribute {
    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 Attribute> for &'l str {
    fn from(input: &'l Attribute) -> Self { input.as_str() }
}
impl From<Attribute> for tinystr::TinyAsciiStr<8> {
    fn from(input: Attribute) -> Self { input.to_tinystr() }
}
impl writeable::Writeable for Attribute {
    #[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 Attribute {
    #[inline]
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        ::writeable::Writeable::write_to(&self, f)
    }
}
impl Attribute {
    /// 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 [`Attribute`] subtags."]
///
/// # Examples
///
/// Parsing errors don't have to be handled at runtime:
/// ```
/// assert_eq!(
#[doc = "  icu_locale_core::extensions::unicode::attribute!(\"foo12\"),"]
#[doc =
"  \"foo12\".parse::<icu_locale_core::extensions::unicode::Attribute>().unwrap()"]
/// );
/// ```
///
/// Invalid input is a compile failure:
/// ```compile_fail,E0080
#[doc = "icu_locale_core::extensions::unicode::attribute!(\"no\");"]
/// ```
///
#[doc = "[`Attribute`]: crate::extensions::unicode::Attribute"]
#[macro_export]
#[doc(hidden)]
macro_rules! extensions_unicode_attribute {
    ($string : literal) =>
    {
        const
        {
            use crate :: extensions :: unicode :: Attribute; match Attribute
            :: try_from_utf8($string.as_bytes())
            {
                Ok(r) => r, #[allow(clippy :: panic)] _ => panic!
                (concat!
                ("Invalid ", stringify! (extensions), "::", stringify!
                (unicode), "::", stringify! (Attribute), ": ", $string)),
            }
        }
    };
}
#[doc(inline)]
pub use extensions_unicode_attribute as attribute;
unsafe impl zerovec::ule::ULE for Attribute {
    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<8> for Attribute {
    const NICHE_BIT_PATTERN: [u8; 8] =
        <tinystr::TinyAsciiStr<8>>::NICHE_BIT_PATTERN;
}
impl zerovec::ule::AsULE for Attribute {
    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 Attribute {
    type Container = zerovec::ZeroVec<'a, Attribute>;
    type Slice = zerovec::ZeroSlice<Attribute>;
    type GetType = Attribute;
    type OwnedType = Attribute;
}impl_tinystr_subtag!(
6    /// An attribute used in a set of [`Attributes`](super::Attributes).
7    ///
8    /// An attribute has to be a sequence of alphanumerical characters no
9    /// shorter than three and no longer than eight characters.
10    ///
11    ///
12    /// # Examples
13    ///
14    /// ```
15    /// use icu::locale::extensions::unicode::{attribute, Attribute};
16    ///
17    /// let attr: Attribute =
18    ///     "buddhist".parse().expect("Failed to parse an Attribute.");
19    ///
20    /// assert_eq!(attr, attribute!("buddhist"));
21    /// ```
22    Attribute,
23    extensions::unicode,
24    attribute,
25    extensions_unicode_attribute,
26    3..=8,
27    s,
28    s.is_ascii_alphanumeric(),
29    s.to_ascii_lowercase(),
30    s.is_ascii_alphanumeric() && s.is_ascii_lowercase(),
31    InvalidExtension,
32    ["foo12"],
33    ["no", "toolooong"],
34);