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 ).
45#[repr(transparent)]
#[doc = r" A key used in a list of [`Keywords`](super::Keywords)."]
#[doc = r""]
#[doc =
r" The key has to be a two ASCII alphanumerical characters long, with the first"]
#[doc = r" character being alphanumeric, and the second being alphabetic."]
#[doc = r""]
#[doc = r""]
#[doc = r" # Examples"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" use icu::locale::extensions::unicode::Key;"]
#[doc = r""]
#[doc = r#" assert!("ca".parse::<Key>().is_ok());"#]
#[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 :: unicode ::Key;"]
///
#[doc = "assert!(Key::try_from_str(\"ca\").is_ok());"]
#[doc = "assert!(Key::try_from_str(\"a\").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_alphanumeric() &&
s.all_bytes()[1].is_ascii_alphabetic() =>
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()[0].is_ascii_digit()) &&
s.all_bytes()[1].is_ascii_lowercase()) {
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::unicode::key!(\"ca\"),"]
#[doc =
" \"ca\".parse::<icu_locale_core::extensions::unicode::Key>().unwrap()"]
/// );
/// ```
///
/// Invalid input is a compile failure:
/// ```compile_fail,E0080
#[doc = "icu_locale_core::extensions::unicode::key!(\"a\");"]
/// ```
///
#[doc = "[`Key`]: crate::extensions::unicode::Key"]
#[macro_export]
#[doc(hidden)]
macro_rules! extensions_unicode_key {
($string : literal) =>
{
const
{
use crate :: extensions :: unicode :: Key; match Key ::
try_from_utf8($string.as_bytes())
{
Ok(r) => r, #[allow(clippy :: panic)] _ => panic!
(concat!
("Invalid ", stringify! (extensions), "::", stringify!
(unicode), "::", stringify! (Key), ": ", $string)),
}
}
};
}
#[doc(inline)]
pub use extensions_unicode_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 [`Keywords`](super::Keywords).
7 ///
8 /// The key has to be a two ASCII alphanumerical characters long, with the first
9 /// character being alphanumeric, and the second being alphabetic.
10 ///
11 ///
12 /// # Examples
13 ///
14 /// ```
15 /// use icu::locale::extensions::unicode::Key;
16 ///
17 /// assert!("ca".parse::<Key>().is_ok());
18 /// ```
19Key,
20 extensions::unicode,
21 key,
22extensions_unicode_key,
232..=2,
24 s,
25 s.all_bytes()[0].is_ascii_alphanumeric() && s.all_bytes()[1].is_ascii_alphabetic(),
26 s.to_ascii_lowercase(),
27 (s.all_bytes()[0].is_ascii_lowercase() || s.all_bytes()[0].is_ascii_digit())
28 && s.all_bytes()[1].is_ascii_lowercase(),
29 InvalidExtension,
30 ["ca", "8a"],
31 ["a", "a8", "abc"],
32);