diff options
Diffstat (limited to 'vendor/icu_locid/src')
21 files changed, 569 insertions, 415 deletions
diff --git a/vendor/icu_locid/src/extensions/mod.rs b/vendor/icu_locid/src/extensions/mod.rs index 42bfcd3c9..a6a189b11 100644 --- a/vendor/icu_locid/src/extensions/mod.rs +++ b/vendor/icu_locid/src/extensions/mod.rs @@ -102,11 +102,11 @@ impl ExtensionType { #[derive(Debug, Default, PartialEq, Eq, Clone, Hash)] #[non_exhaustive] pub struct Extensions { - /// A representation of the data for a Unicode extension, when present in the locale identifer. + /// A representation of the data for a Unicode extension, when present in the locale identifier. pub unicode: Unicode, - /// A representation of the data for a transform extension, when present in the locale identifer. + /// A representation of the data for a transform extension, when present in the locale identifier. pub transform: Transform, - /// A representation of the data for a private-use extension, when present in the locale identifer. + /// A representation of the data for a private-use extension, when present in the locale identifier. pub private: Private, /// A sequence of any other extensions that are present in the locale identifier but are not formally /// [defined](https://unicode.org/reports/tr35/) and represented explicitly as [`Unicode`], [`Transform`], @@ -210,19 +210,33 @@ impl Extensions { let mut private = None; let mut other = Vec::new(); - let mut st = iter.next(); - while let Some(subtag) = st { + while let Some(subtag) = iter.next() { + if subtag.is_empty() { + return Err(ParserError::InvalidExtension); + } match subtag.get(0).map(|b| ExtensionType::try_from_byte(*b)) { Some(Ok(ExtensionType::Unicode)) => { + if unicode.is_some() { + return Err(ParserError::DuplicatedExtension); + } unicode = Some(Unicode::try_from_iter(iter)?); } Some(Ok(ExtensionType::Transform)) => { + if transform.is_some() { + return Err(ParserError::DuplicatedExtension); + } transform = Some(Transform::try_from_iter(iter)?); } Some(Ok(ExtensionType::Private)) => { + if private.is_some() { + return Err(ParserError::DuplicatedExtension); + } private = Some(Private::try_from_iter(iter)?); } Some(Ok(ExtensionType::Other(ext))) => { + if other.iter().any(|o: &Other| o.get_ext_byte() == ext) { + return Err(ParserError::DuplicatedExtension); + } let parsed = Other::try_from_iter(ext, iter)?; if let Err(idx) = other.binary_search(&parsed) { other.insert(idx, parsed); @@ -230,11 +244,8 @@ impl Extensions { return Err(ParserError::InvalidExtension); } } - None => {} _ => return Err(ParserError::InvalidExtension), } - - st = iter.next(); } Ok(Self { @@ -283,7 +294,7 @@ impl_writeable_for_each_subtag_str_no_test!(Extensions); fn test_writeable() { use crate::Locale; use writeable::assert_writeable_eq; - assert_writeable_eq!(Extensions::new(), "",); + assert_writeable_eq!(Extensions::new(), ""); assert_writeable_eq!( "my-t-my-d0-zawgyi".parse::<Locale>().unwrap().extensions, "t-my-d0-zawgyi", diff --git a/vendor/icu_locid/src/extensions/other/mod.rs b/vendor/icu_locid/src/extensions/other/mod.rs index 36dbc49b6..44d5c9cf8 100644 --- a/vendor/icu_locid/src/extensions/other/mod.rs +++ b/vendor/icu_locid/src/extensions/other/mod.rs @@ -41,13 +41,16 @@ pub use subtag::Subtag; /// let subtag2: Subtag = "bar".parse().expect("Failed to parse a Subtag."); /// /// let other = Other::from_vec_unchecked(b'a', vec![subtag1, subtag2]); -/// assert_eq!(&other.to_string(), "-a-foo-bar"); +/// assert_eq!(&other.to_string(), "a-foo-bar"); /// ``` /// /// [`Other Use Extensions`]: https://unicode.org/reports/tr35/#other_extensions /// [`Unicode Locale Identifier`]: https://unicode.org/reports/tr35/#Unicode_locale_identifier #[derive(Clone, PartialEq, Eq, Debug, Default, Hash, PartialOrd, Ord)] -pub struct Other((u8, Vec<Subtag>)); +pub struct Other { + ext: u8, + keys: Vec<Subtag>, +} impl Other { /// A constructor which takes a pre-sorted list of [`Subtag`]. @@ -65,11 +68,11 @@ impl Other { /// let subtag2: Subtag = "bar".parse().expect("Failed to parse a Subtag."); /// /// let other = Other::from_vec_unchecked(b'a', vec![subtag1, subtag2]); - /// assert_eq!(&other.to_string(), "-a-foo-bar"); + /// assert_eq!(&other.to_string(), "a-foo-bar"); /// ``` - pub fn from_vec_unchecked(ext: u8, input: Vec<Subtag>) -> Self { + pub fn from_vec_unchecked(ext: u8, keys: Vec<Subtag>) -> Self { assert!(ext.is_ascii_alphabetic()); - Self((ext, input)) + Self { ext, keys } } pub(crate) fn try_from_iter(ext: u8, iter: &mut SubtagIterator) -> Result<Self, ParserError> { @@ -89,6 +92,22 @@ impl Other { Ok(Self::from_vec_unchecked(ext, keys)) } + /// Gets the tag character for this extension as a &str. + /// + /// # Examples + /// + /// ``` + /// use icu::locid::Locale; + /// + /// let loc: Locale = "und-a-hello-world".parse().unwrap(); + /// let other_ext = &loc.extensions.other[0]; + /// assert_eq!(other_ext.get_ext_str(), "a"); + /// ``` + pub fn get_ext_str(&self) -> &str { + debug_assert!(self.ext.is_ascii_alphabetic()); + unsafe { core::str::from_utf8_unchecked(core::slice::from_ref(&self.ext)) } + } + /// Gets the tag character for this extension as a char. /// /// # Examples @@ -101,7 +120,7 @@ impl Other { /// assert_eq!(other_ext.get_ext(), 'a'); /// ``` pub fn get_ext(&self) -> char { - self.get_ext_byte() as char + self.ext as char } /// Gets the tag character for this extension as a byte. @@ -116,19 +135,15 @@ impl Other { /// assert_eq!(other_ext.get_ext_byte(), b'a'); /// ``` pub fn get_ext_byte(&self) -> u8 { - self.0 .0 + self.ext } pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F) -> Result<(), E> where F: FnMut(&str) -> Result<(), E>, { - let (ext, keys) = &self.0; - debug_assert!(ext.is_ascii_alphabetic()); - // Safety: ext is ascii_alphabetic, so it is valid UTF-8 - let ext_str = unsafe { core::str::from_utf8_unchecked(core::slice::from_ref(ext)) }; - f(ext_str)?; - keys.iter().map(|t| t.as_str()).try_for_each(f) + f(self.get_ext_str())?; + self.keys.iter().map(|t| t.as_str()).try_for_each(f) } } @@ -136,10 +151,8 @@ writeable::impl_display_with_writeable!(Other); impl writeable::Writeable for Other { fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result { - let (ext, keys) = &self.0; - sink.write_char('-')?; - sink.write_char(*ext as char)?; - for key in keys.iter() { + sink.write_str(self.get_ext_str())?; + for key in self.keys.iter() { sink.write_char('-')?; writeable::Writeable::write_to(key, sink)?; } @@ -148,10 +161,20 @@ impl writeable::Writeable for Other { } fn writeable_length_hint(&self) -> writeable::LengthHint { - let mut result = writeable::LengthHint::exact(2); - for key in self.0 .1.iter() { + let mut result = writeable::LengthHint::exact(1); + for key in self.keys.iter() { result += writeable::Writeable::writeable_length_hint(key) + 1; } result } + + fn write_to_string(&self) -> alloc::borrow::Cow<str> { + if self.keys.is_empty() { + return alloc::borrow::Cow::Borrowed(self.get_ext_str()); + } + let mut string = + alloc::string::String::with_capacity(self.writeable_length_hint().capacity()); + let _ = self.write_to(&mut string); + alloc::borrow::Cow::Owned(string) + } } diff --git a/vendor/icu_locid/src/extensions/other/subtag.rs b/vendor/icu_locid/src/extensions/other/subtag.rs index 60995c395..ad4d6a0f2 100644 --- a/vendor/icu_locid/src/extensions/other/subtag.rs +++ b/vendor/icu_locid/src/extensions/other/subtag.rs @@ -11,11 +11,9 @@ impl_tinystr_subtag!( /// # Examples /// /// ``` - /// use icu::locid::extensions::other::Subtag; + /// use icu::locid::extensions_other_subtag as subtag; /// - /// let subtag: Subtag = "Foo".parse().expect("Failed to parse a Subtag."); - /// - /// assert_eq!(subtag.as_str(), "foo"); + /// assert_eq!(subtag!("Foo").as_str(), "foo"); /// ``` Subtag, extensions::other::Subtag, diff --git a/vendor/icu_locid/src/extensions/private/mod.rs b/vendor/icu_locid/src/extensions/private/mod.rs index 13090c94a..8382d166f 100644 --- a/vendor/icu_locid/src/extensions/private/mod.rs +++ b/vendor/icu_locid/src/extensions/private/mod.rs @@ -13,16 +13,18 @@ //! # Examples //! //! ``` -//! use icu::locid::extensions::private::{Private, Subtag}; -//! use icu::locid::Locale; +//! use icu::locid::extensions_private_subtag as subtag; +//! use icu::locid::{locale, Locale}; //! //! let mut loc: Locale = "en-US-x-foo-faa".parse().expect("Parsing failed."); //! -//! let subtag: Subtag = "foo".parse().expect("Parsing subtag failed."); -//! assert!(loc.extensions.private.contains(&subtag)); -//! assert_eq!(loc.extensions.private.iter().next(), Some(&subtag)); +//! assert!(loc.extensions.private.contains(&subtag!("foo"))); +//! assert_eq!(loc.extensions.private.iter().next(), Some(&subtag!("foo"))); +//! //! loc.extensions.private.clear(); -//! assert_eq!(loc.to_string(), "en-US"); +//! +//! assert!(loc.extensions.private.is_empty()); +//! assert_eq!(loc, locale!("en-US")); //! ``` mod other; @@ -50,7 +52,7 @@ use crate::parser::SubtagIterator; /// let subtag2: Subtag = "bar".parse().expect("Failed to parse a Subtag."); /// /// let private = Private::from_vec_unchecked(vec![subtag1, subtag2]); -/// assert_eq!(&private.to_string(), "-x-foo-bar"); +/// assert_eq!(&private.to_string(), "x-foo-bar"); /// ``` /// /// [`Private Use Extensions`]: https://unicode.org/reports/tr35/#pu_extensions @@ -84,7 +86,7 @@ impl Private { /// let subtag2: Subtag = "bar".parse().expect("Failed to parse a Subtag."); /// /// let private = Private::from_vec_unchecked(vec![subtag1, subtag2]); - /// assert_eq!(&private.to_string(), "-x-foo-bar"); + /// assert_eq!(&private.to_string(), "x-foo-bar"); /// ``` pub fn from_vec_unchecked(input: Vec<Subtag>) -> Self { Self(input) @@ -101,11 +103,11 @@ impl Private { /// let subtag2: Subtag = "bar".parse().expect("Failed to parse a Subtag."); /// let mut private = Private::from_vec_unchecked(vec![subtag1, subtag2]); /// - /// assert_eq!(&private.to_string(), "-x-foo-bar"); + /// assert_eq!(&private.to_string(), "x-foo-bar"); /// /// private.clear(); /// - /// assert_eq!(&private.to_string(), ""); + /// assert_eq!(private, Private::new()); /// ``` pub fn clear(&mut self) { self.0.clear(); @@ -138,7 +140,7 @@ impl writeable::Writeable for Private { if self.is_empty() { return Ok(()); } - sink.write_str("-x")?; + sink.write_str("x")?; for key in self.iter() { sink.write_char('-')?; writeable::Writeable::write_to(key, sink)?; @@ -150,7 +152,7 @@ impl writeable::Writeable for Private { if self.is_empty() { return writeable::LengthHint::exact(0); } - let mut result = writeable::LengthHint::exact(2); + let mut result = writeable::LengthHint::exact(1); for key in self.iter() { result += writeable::Writeable::writeable_length_hint(key) + 1; } diff --git a/vendor/icu_locid/src/extensions/transform/fields.rs b/vendor/icu_locid/src/extensions/transform/fields.rs index ca10000a7..f08581a87 100644 --- a/vendor/icu_locid/src/extensions/transform/fields.rs +++ b/vendor/icu_locid/src/extensions/transform/fields.rs @@ -25,10 +25,10 @@ use super::Value; /// /// ``` /// use icu::locid::extensions::transform::{Fields, Key, Value}; +/// use icu::locid::extensions_transform_key as key; /// -/// let key: Key = "h0".parse().expect("Failed to parse a Key."); -/// let value: Value = "hybrid".parse().expect("Failed to parse a Value."); -/// let fields: Fields = vec![(key, value)].into_iter().collect(); +/// let value = "hybrid".parse::<Value>().expect("Failed to parse a Value."); +/// let fields = vec![(key!("h0"), value)].into_iter().collect::<Fields>(); /// /// assert_eq!(&fields.to_string(), "h0-hybrid"); /// ``` @@ -76,17 +76,17 @@ impl Fields { /// # Examples /// /// ``` - /// use icu::locid::extensions::transform::{Fields, Key, Value}; + /// use icu::locid::extensions::transform::{Fields, Value}; + /// use icu::locid::extensions_transform_key as key; /// - /// let key: Key = "h0".parse().expect("Failed to parse a Key."); - /// let value: Value = "hybrid".parse().expect("Failed to parse a Value."); - /// let mut fields: Fields = vec![(key, value)].into_iter().collect(); + /// let value = "hybrid".parse::<Value>().expect("Failed to parse a Value."); + /// let mut fields = vec![(key!("h0"), value)].into_iter().collect::<Fields>(); /// /// assert_eq!(&fields.to_string(), "h0-hybrid"); /// /// fields.clear(); /// - /// assert_eq!(&fields.to_string(), ""); + /// assert_eq!(fields, Fields::new()); /// ``` pub fn clear(&mut self) -> Self { core::mem::take(self) @@ -122,16 +122,14 @@ impl Fields { /// /// ``` /// use icu::locid::extensions::transform::{Fields, Key, Value}; + /// use icu::locid::extensions_transform_key as key; /// - /// let key: Key = "h0".parse().expect("Failed to parse a Key."); - /// let value: Value = "hybrid".parse().expect("Failed to parse a Value."); - /// let mut fields: Fields = vec![(key, value)].into_iter().collect(); + /// let value = "hybrid".parse::<Value>().unwrap(); + /// let fields = vec![(key!("h0"), value.clone())] + /// .into_iter() + /// .collect::<Fields>(); /// - /// let key: Key = "h0".parse().expect("Failed to parse a Key."); - /// assert_eq!( - /// fields.get(&key).map(|v| v.to_string()), - /// Some("hybrid".to_string()) - /// ); + /// assert_eq!(fields.get(&key!("h0")), Some(&value)); /// ``` pub fn get<Q>(&self, key: &Q) -> Option<&Value> where diff --git a/vendor/icu_locid/src/extensions/transform/mod.rs b/vendor/icu_locid/src/extensions/transform/mod.rs index a8c605146..7b97d87f6 100644 --- a/vendor/icu_locid/src/extensions/transform/mod.rs +++ b/vendor/icu_locid/src/extensions/transform/mod.rs @@ -28,7 +28,7 @@ //! assert!(loc.extensions.transform.fields.contains_key(&key)); //! assert_eq!(loc.extensions.transform.fields.get(&key), Some(&value)); //! -//! assert_eq!(&loc.extensions.transform.to_string(), "-t-es-AR-h0-hybrid"); +//! assert_eq!(&loc.extensions.transform.to_string(), "t-es-AR-h0-hybrid"); //! ``` mod fields; mod key; @@ -208,7 +208,7 @@ impl writeable::Writeable for Transform { if self.is_empty() { return Ok(()); } - sink.write_str("-t")?; + sink.write_str("t")?; if let Some(lang) = &self.lang { sink.write_char('-')?; writeable::Writeable::write_to(lang, sink)?; @@ -224,7 +224,7 @@ impl writeable::Writeable for Transform { if self.is_empty() { return writeable::LengthHint::exact(0); } - let mut result = writeable::LengthHint::exact(2); + let mut result = writeable::LengthHint::exact(1); if let Some(lang) = &self.lang { result += writeable::Writeable::writeable_length_hint(lang) + 1; } diff --git a/vendor/icu_locid/src/extensions/transform/value.rs b/vendor/icu_locid/src/extensions/transform/value.rs index 84468361a..f908b0208 100644 --- a/vendor/icu_locid/src/extensions/transform/value.rs +++ b/vendor/icu_locid/src/extensions/transform/value.rs @@ -2,7 +2,7 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::parser::{get_subtag_iterator, ParserError}; +use crate::parser::{ParserError, SubtagIterator}; use alloc::vec; use alloc::vec::Vec; use core::ops::RangeInclusive; @@ -16,20 +16,18 @@ use tinystr::TinyAsciiStr; /// Each part of the sequence has to be no shorter than three characters and no /// longer than 8. /// -/// /// # Examples /// /// ``` /// use icu::locid::extensions::transform::Value; /// -/// let value1: Value = "hybrid".parse().expect("Failed to parse a Value."); -/// let value2: Value = -/// "hybrid-foobar".parse().expect("Failed to parse a Value."); +/// "hybrid".parse::<Value>().expect("Valid Value."); +/// +/// "hybrid-foobar".parse::<Value>().expect("Valid Value."); /// -/// assert_eq!(&value1.to_string(), "hybrid"); -/// assert_eq!(&value2.to_string(), "hybrid-foobar"); +/// "no".parse::<Value>().expect_err("Invalid Value."); /// ``` -#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord, Default)] pub struct Value(Vec<TinyAsciiStr<{ *TYPE_LENGTH.end() }>>); const TYPE_LENGTH: RangeInclusive<usize> = 3..=8; @@ -45,14 +43,12 @@ impl Value { /// use icu::locid::extensions::transform::Value; /// /// let value = Value::try_from_bytes(b"hybrid").expect("Parsing failed."); - /// - /// assert_eq!(&value.to_string(), "hybrid"); /// ``` pub fn try_from_bytes(input: &[u8]) -> Result<Self, ParserError> { let mut v = vec![]; let mut has_value = false; - for subtag in get_subtag_iterator(input) { + for subtag in SubtagIterator::new(input) { if !Self::is_type_subtag(subtag) { return Err(ParserError::InvalidExtension); } @@ -116,4 +112,19 @@ impl FromStr for Value { } } -impl_writeable_for_tinystr_list!(Value, "true", "hybrid", "foobar"); +impl_writeable_for_each_subtag_str_no_test!(Value, selff, selff.0.is_empty() => alloc::borrow::Cow::Borrowed("true")); + +#[test] +fn test_writeable() { + use writeable::assert_writeable_eq; + + let hybrid = "hybrid".parse().unwrap(); + let foobar = "foobar".parse().unwrap(); + + assert_writeable_eq!(Value::default(), "true"); + assert_writeable_eq!(Value::from_vec_unchecked(vec![hybrid]), "hybrid"); + assert_writeable_eq!( + Value::from_vec_unchecked(vec![hybrid, foobar]), + "hybrid-foobar" + ); +} diff --git a/vendor/icu_locid/src/extensions/unicode/attributes.rs b/vendor/icu_locid/src/extensions/unicode/attributes.rs index 1f9536bfa..e58fb04da 100644 --- a/vendor/icu_locid/src/extensions/unicode/attributes.rs +++ b/vendor/icu_locid/src/extensions/unicode/attributes.rs @@ -79,18 +79,19 @@ impl Attributes { /// /// ``` /// use icu::locid::extensions::unicode::{Attribute, Attributes}; + /// use icu::locid::extensions_unicode_attribute as attribute; + /// use writeable::assert_writeable_eq; /// - /// let attribute1: Attribute = "foobar".parse().expect("Parsing failed."); - /// let attribute2: Attribute = "testing".parse().expect("Parsing failed."); - /// let mut v = vec![attribute1, attribute2]; - /// - /// let mut attributes: Attributes = Attributes::from_vec_unchecked(v); + /// let mut attributes = Attributes::from_vec_unchecked(vec![ + /// attribute!("foobar"), + /// attribute!("testing"), + /// ]); /// - /// assert_eq!(attributes.to_string(), "foobar-testing"); + /// assert_writeable_eq!(attributes, "foobar-testing"); /// /// attributes.clear(); /// - /// assert_eq!(attributes.to_string(), ""); + /// assert_writeable_eq!(attributes, ""); /// ``` pub fn clear(&mut self) -> Self { core::mem::take(self) diff --git a/vendor/icu_locid/src/extensions/unicode/keywords.rs b/vendor/icu_locid/src/extensions/unicode/keywords.rs index dc9a15921..580cacaf1 100644 --- a/vendor/icu_locid/src/extensions/unicode/keywords.rs +++ b/vendor/icu_locid/src/extensions/unicode/keywords.rs @@ -29,11 +29,14 @@ use crate::ordering::SubtagOrderingResult; /// Manually build up a [`Keywords`] object: /// /// ``` -/// use icu::locid::extensions::unicode::{Key, Keywords, Value}; +/// use icu::locid::{ +/// extensions::unicode::Keywords, extensions_unicode_key as key, +/// extensions_unicode_value as value, locale, +/// }; /// -/// let key: Key = "hc".parse().expect("Failed to parse a Key."); -/// let value: Value = "h23".parse().expect("Failed to parse a Value."); -/// let keywords: Keywords = vec![(key, value)].into_iter().collect(); +/// let keywords = vec![(key!("hc"), value!("h23"))] +/// .into_iter() +/// .collect::<Keywords>(); /// /// assert_eq!(&keywords.to_string(), "hc-h23"); /// ``` @@ -113,15 +116,16 @@ impl Keywords { /// # Examples /// /// ``` - /// use icu::locid::extensions::unicode::{Key, Keywords, Value}; - /// use litemap::LiteMap; + /// use icu::locid::{ + /// extensions::unicode::Keywords, extensions_unicode_key as key, + /// extensions_unicode_value as value, + /// }; /// - /// let key: Key = "ca".parse().expect("Failed to parse a Key."); - /// let value: Value = "gregory".parse().expect("Failed to parse a Value."); - /// let keywords: Keywords = vec![(key, value)].into_iter().collect(); + /// let keywords = vec![(key!("ca"), value!("gregory"))] + /// .into_iter() + /// .collect::<Keywords>(); /// - /// let key: Key = "ca".parse().expect("Failed to parse a Key."); - /// assert!(&keywords.contains_key(&key)); + /// assert!(&keywords.contains_key(&key!("ca"))); /// ``` pub fn contains_key<Q>(&self, key: &Q) -> bool where @@ -137,17 +141,16 @@ impl Keywords { /// # Examples /// /// ``` - /// use icu::locid::extensions::unicode::{Key, Keywords, Value}; + /// use icu::locid::{ + /// extensions::unicode::Keywords, extensions_unicode_key as key, + /// extensions_unicode_value as value, + /// }; /// - /// let key: Key = "ca".parse().expect("Failed to parse a Key."); - /// let value: Value = "buddhist".parse().expect("Failed to parse a Value."); - /// let keywords: Keywords = vec![(key, value)].into_iter().collect(); + /// let keywords = vec![(key!("ca"), value!("buddhist"))] + /// .into_iter() + /// .collect::<Keywords>(); /// - /// let key: Key = "ca".parse().expect("Failed to parse a Key."); - /// assert_eq!( - /// keywords.get(&key).map(|v| v.to_string()), - /// Some("buddhist".to_string()) - /// ); + /// assert_eq!(keywords.get(&key!("ca")), Some(&value!("buddhist"))); /// ``` pub fn get<Q>(&self, key: &Q) -> Option<&Value> where @@ -164,20 +167,19 @@ impl Keywords { /// # Examples /// /// ``` - /// use icu::locid::extensions::unicode::{Key, Keywords, Value}; + /// use icu::locid::{ + /// extensions::unicode::Keywords, extensions_unicode_key as key, + /// extensions_unicode_value as value, + /// }; /// - /// let key: Key = "ca".parse().expect("Failed to parse a Key."); - /// let value: Value = "buddhist".parse().expect("Failed to parse a Value."); - /// let mut keywords: Keywords = vec![(key, value)].into_iter().collect(); + /// let mut keywords = vec![(key!("ca"), value!("buddhist"))] + /// .into_iter() + /// .collect::<Keywords>(); /// - /// let key: Key = "ca".parse().expect("Failed to parse a Key."); - /// if let Some(value) = keywords.get_mut(&key) { - /// *value = "gregory".parse().expect("Failed to parse a Value."); + /// if let Some(value) = keywords.get_mut(&key!("ca")) { + /// *value = value!("gregory"); /// } - /// assert_eq!( - /// keywords.get(&key).map(|v| v.to_string()), - /// Some("gregory".to_string()) - /// ); + /// assert_eq!(keywords.get(&key!("ca")), Some(&value!("gregory"))); /// ``` pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut Value> where @@ -308,7 +310,6 @@ impl Keywords { /// .extensions /// .unicode /// .keywords; - /// assert_eq!(a, a_kwds.to_string()); /// assert!(a_kwds.strict_cmp(a.as_bytes()) == Ordering::Equal); /// assert!(a_kwds.strict_cmp(b.as_bytes()) == Ordering::Less); /// } diff --git a/vendor/icu_locid/src/extensions/unicode/mod.rs b/vendor/icu_locid/src/extensions/unicode/mod.rs index fabf1036c..687a8c383 100644 --- a/vendor/icu_locid/src/extensions/unicode/mod.rs +++ b/vendor/icu_locid/src/extensions/unicode/mod.rs @@ -11,21 +11,24 @@ //! # Examples //! //! ``` -//! use icu::locid::extensions::unicode::{Attribute, Key, Unicode, Value}; -//! use icu::locid::{LanguageIdentifier, Locale}; +//! use icu::locid::Locale; +//! use icu::locid::{ +//! extensions::unicode::Unicode, +//! extensions_unicode_attribute as attribute, +//! extensions_unicode_key as key, extensions_unicode_value as value, +//! }; //! -//! let mut loc: Locale = -//! "en-US-u-foobar-hc-h12".parse().expect("Parsing failed."); +//! let loc: Locale = "en-US-u-foobar-hc-h12".parse().expect("Parsing failed."); //! -//! let key: Key = "hc".parse().expect("Parsing key failed."); -//! let value: Value = "h12".parse().expect("Parsing value failed."); -//! let attribute: Attribute = -//! "foobar".parse().expect("Parsing attribute failed."); -//! -//! assert_eq!(loc.extensions.unicode.keywords.get(&key), Some(&value)); -//! assert!(loc.extensions.unicode.attributes.contains(&attribute)); -//! -//! assert_eq!(&loc.extensions.unicode.to_string(), "-u-foobar-hc-h12"); +//! assert_eq!( +//! loc.extensions.unicode.keywords.get(&key!("hc")), +//! Some(&value!("h12")) +//! ); +//! assert!(loc +//! .extensions +//! .unicode +//! .attributes +//! .contains(&attribute!("foobar"))); //! ``` mod attribute; mod attributes; @@ -60,15 +63,18 @@ use litemap::LiteMap; /// # Examples /// /// ``` -/// use icu::locid::extensions::unicode::{Key, Value}; /// use icu::locid::Locale; +/// use icu::locid::{ +/// extensions_unicode_key as key, extensions_unicode_value as value, +/// }; /// -/// let mut loc: Locale = +/// let loc: Locale = /// "de-u-hc-h12-ca-buddhist".parse().expect("Parsing failed."); /// -/// let key: Key = "ca".parse().expect("Parsing key failed."); -/// let value: Value = "buddhist".parse().expect("Parsing value failed."); -/// assert_eq!(loc.extensions.unicode.keywords.get(&key), Some(&value)); +/// assert_eq!( +/// loc.extensions.unicode.keywords.get(&key!("ca")), +/// Some(&value!("buddhist")) +/// ); /// ``` #[derive(Clone, PartialEq, Eq, Debug, Default, Hash, PartialOrd, Ord)] #[allow(clippy::exhaustive_structs)] // spec-backed stable datastructure @@ -205,7 +211,7 @@ impl writeable::Writeable for Unicode { if self.is_empty() { return Ok(()); } - sink.write_str("-u")?; + sink.write_str("u")?; if !self.attributes.is_empty() { sink.write_char('-')?; writeable::Writeable::write_to(&self.attributes, sink)?; @@ -221,7 +227,7 @@ impl writeable::Writeable for Unicode { if self.is_empty() { return writeable::LengthHint::exact(0); } - let mut result = writeable::LengthHint::exact(2); + let mut result = writeable::LengthHint::exact(1); if !self.attributes.is_empty() { result += writeable::Writeable::writeable_length_hint(&self.attributes) + 1; } diff --git a/vendor/icu_locid/src/extensions/unicode/value.rs b/vendor/icu_locid/src/extensions/unicode/value.rs index ce9982a4c..e6374372c 100644 --- a/vendor/icu_locid/src/extensions/unicode/value.rs +++ b/vendor/icu_locid/src/extensions/unicode/value.rs @@ -3,7 +3,7 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::helpers::ShortVec; -use crate::parser::{get_subtag_iterator, ParserError}; +use crate::parser::{ParserError, SubtagIterator}; use alloc::vec::Vec; use core::ops::RangeInclusive; use core::str::FromStr; @@ -20,20 +20,21 @@ use tinystr::TinyAsciiStr; /// # Examples /// /// ``` -/// use icu::locid::extensions::unicode::Value; -/// -/// let value1: Value = "gregory".parse().expect("Failed to parse a Value."); -/// let value2: Value = -/// "islamic-civil".parse().expect("Failed to parse a Value."); -/// let value3: Value = "true".parse().expect("Failed to parse a Value."); +/// use icu::locid::{ +/// extensions::unicode::Value, extensions_unicode_value as value, +/// }; +/// use writeable::assert_writeable_eq; /// -/// assert_eq!(&value1.to_string(), "gregory"); -/// assert_eq!(&value2.to_string(), "islamic-civil"); +/// assert_writeable_eq!(value!("gregory"), "gregory"); +/// assert_writeable_eq!( +/// "islamic-civil".parse::<Value>().unwrap(), +/// "islamic-civil" +/// ); /// -/// // The value "true" is special-cased to an empty value -/// assert_eq!(&value3.to_string(), ""); +/// // The value "true" has the special, empty string representation +/// assert_eq!(value!("true").to_string(), ""); /// ``` -#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord, Default)] pub struct Value(ShortVec<TinyAsciiStr<{ *VALUE_LENGTH.end() }>>); const VALUE_LENGTH: RangeInclusive<usize> = 3..=8; @@ -48,15 +49,13 @@ impl Value { /// ``` /// use icu::locid::extensions::unicode::Value; /// - /// let value = Value::try_from_bytes(b"buddhist").expect("Parsing failed."); - /// - /// assert_eq!(&value.to_string(), "buddhist"); + /// Value::try_from_bytes(b"buddhist").expect("Parsing failed."); /// ``` pub fn try_from_bytes(input: &[u8]) -> Result<Self, ParserError> { let mut v = ShortVec::new(); if !input.is_empty() { - for subtag in get_subtag_iterator(input) { + for subtag in SubtagIterator::new(input) { let val = Self::subtag_from_bytes(subtag)?; if let Some(val) = val { v.push(val); @@ -153,7 +152,7 @@ impl FromStr for Value { } } -impl_writeable_for_tinystr_list!(Value, "", "islamic", "civil"); +impl_writeable_for_subtag_list!(Value, "islamic", "civil"); /// A macro allowing for compile-time construction of valid Unicode [`Value`] subtag. /// diff --git a/vendor/icu_locid/src/helpers.rs b/vendor/icu_locid/src/helpers.rs index e617ded5d..e5889a7b0 100644 --- a/vendor/icu_locid/src/helpers.rs +++ b/vendor/icu_locid/src/helpers.rs @@ -115,7 +115,7 @@ impl<T> ShortVec<T> { #[allow(clippy::unwrap_used)] // we know that the vec has exactly one element left 1 => (ShortVec::Single(v.pop().unwrap()), removed_item), - // v has atleast 2 elements, create a Multi variant + // v has at least 2 elements, create a Multi variant _ => (ShortVec::Multi(v), removed_item), } } @@ -387,6 +387,7 @@ macro_rules! impl_tinystr_subtag { } impl writeable::Writeable for $name { + #[inline] fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result { sink.write_str(self.as_str()) } @@ -394,6 +395,10 @@ macro_rules! impl_tinystr_subtag { fn writeable_length_hint(&self) -> writeable::LengthHint { writeable::LengthHint::exact(self.0.len()) } + #[inline] + fn write_to_string(&self) -> alloc::borrow::Cow<str> { + alloc::borrow::Cow::Borrowed(self.0.as_str()) + } } writeable::impl_display_with_writeable!($name); @@ -546,7 +551,7 @@ macro_rules! impl_tinystr_subtag { } macro_rules! impl_writeable_for_each_subtag_str_no_test { - ($type:tt) => { + ($type:tt $(, $self:ident, $borrow_cond:expr => $borrow:expr)?) => { impl writeable::Writeable for $type { fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result { let mut initial = true; @@ -576,6 +581,20 @@ macro_rules! impl_writeable_for_each_subtag_str_no_test { .expect("infallible"); result } + + $( + fn write_to_string(&self) -> alloc::borrow::Cow<str> { + #[allow(clippy::unwrap_used)] // impl_writeable_for_subtag_list's $borrow uses unwrap + let $self = self; + if $borrow_cond { + $borrow + } else { + let mut output = alloc::string::String::with_capacity(self.writeable_length_hint().capacity()); + let _ = self.write_to(&mut output); + alloc::borrow::Cow::Owned(output) + } + } + )? } writeable::impl_display_with_writeable!($type); @@ -584,7 +603,7 @@ macro_rules! impl_writeable_for_each_subtag_str_no_test { macro_rules! impl_writeable_for_subtag_list { ($type:tt, $sample1:literal, $sample2:literal) => { - impl_writeable_for_each_subtag_str_no_test!($type); + impl_writeable_for_each_subtag_str_no_test!($type, selff, selff.0.len() == 1 => alloc::borrow::Cow::Borrowed(selff.0.as_slice().get(0).unwrap().as_str())); #[test] fn test_writeable() { @@ -594,27 +613,6 @@ macro_rules! impl_writeable_for_subtag_list { $sample1, ); writeable::assert_writeable_eq!( - &$type::from_vec_unchecked(alloc::vec![ - $sample1.parse().unwrap(), - $sample2.parse().unwrap() - ]), - core::concat!($sample1, "-", $sample2), - ); - } - }; -} - -macro_rules! impl_writeable_for_tinystr_list { - ($type:tt, $if_empty:literal, $sample1:literal, $sample2:literal) => { - impl_writeable_for_each_subtag_str_no_test!($type); - - #[test] - fn test_writeable() { - writeable::assert_writeable_eq!( - &$type::from_vec_unchecked(vec![$sample1.parse().unwrap()]), - $sample1, - ); - writeable::assert_writeable_eq!( &$type::from_vec_unchecked(vec![ $sample1.parse().unwrap(), $sample2.parse().unwrap() diff --git a/vendor/icu_locid/src/langid.rs b/vendor/icu_locid/src/langid.rs index fc5435766..b6858c91b 100644 --- a/vendor/icu_locid/src/langid.rs +++ b/vendor/icu_locid/src/langid.rs @@ -7,27 +7,28 @@ use core::str::FromStr; use crate::ordering::SubtagOrderingResult; use crate::parser::{ - get_subtag_iterator, parse_language_identifier, parse_language_identifier_with_single_variant, - ParserError, ParserMode, + parse_language_identifier, parse_language_identifier_with_single_variant, ParserError, + ParserMode, SubtagIterator, }; use crate::subtags; use alloc::string::String; -use alloc::string::ToString; +use writeable::Writeable; /// A core struct representing a [`Unicode BCP47 Language Identifier`]. /// /// # Examples /// /// ``` -/// use icu::locid::{subtags::*, LanguageIdentifier}; +/// use icu::locid::{ +/// langid, subtags_language as language, subtags_region as region, +/// }; /// -/// let li: LanguageIdentifier = "en-US".parse().expect("Failed to parse."); +/// let li = langid!("en-US"); /// -/// assert_eq!(li.language, "en".parse::<Language>().unwrap()); +/// assert_eq!(li.language, language!("en")); /// assert_eq!(li.script, None); -/// assert_eq!(li.region.unwrap(), "US".parse::<Region>().unwrap()); +/// assert_eq!(li.region, Some(region!("US"))); /// assert_eq!(li.variants.len(), 0); -/// assert_eq!(li.to_string(), "en-US"); /// ``` /// /// # Parsing @@ -47,18 +48,17 @@ use alloc::string::ToString; /// # Examples /// /// ``` -/// use icu::locid::{subtags::*, LanguageIdentifier}; +/// use icu::locid::{ +/// langid, subtags_language as language, subtags_region as region, +/// subtags_script as script, subtags_variant as variant, +/// }; /// -/// let li: LanguageIdentifier = -/// "eN_latn_Us-Valencia".parse().expect("Failed to parse."); +/// let li = langid!("eN_latn_Us-Valencia"); /// -/// assert_eq!(li.language, "en".parse::<Language>().unwrap()); -/// assert_eq!(li.script, "Latn".parse::<Script>().ok()); -/// assert_eq!(li.region, "US".parse::<Region>().ok()); -/// assert_eq!( -/// li.variants.get(0), -/// "valencia".parse::<Variant>().ok().as_ref() -/// ); +/// assert_eq!(li.language, language!("en")); +/// assert_eq!(li.script, Some(script!("Latn"))); +/// assert_eq!(li.region, Some(region!("US"))); +/// assert_eq!(li.variants.get(0), Some(&variant!("valencia"))); /// ``` /// /// [`Unicode BCP47 Language Identifier`]: https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier @@ -84,10 +84,7 @@ impl LanguageIdentifier { /// ``` /// use icu::locid::LanguageIdentifier; /// - /// let li = - /// LanguageIdentifier::try_from_bytes(b"en-US").expect("Parsing failed."); - /// - /// assert_eq!(li.to_string(), "en-US"); + /// LanguageIdentifier::try_from_bytes(b"en-US").expect("Parsing failed"); /// ``` pub fn try_from_bytes(v: &[u8]) -> Result<Self, ParserError> { parse_language_identifier(v, ParserMode::LanguageIdentifier) @@ -117,12 +114,12 @@ impl LanguageIdentifier { /// # Examples /// /// ``` - /// use icu::locid::LanguageIdentifier; + /// use icu::locid::{langid, LanguageIdentifier}; /// /// let li = LanguageIdentifier::try_from_locale_bytes(b"en-US-x-posix") /// .expect("Parsing failed."); /// - /// assert_eq!(li.to_string(), "en-US"); + /// assert_eq!(li, langid!("en-US")); /// ``` /// /// This method should be used for input that may be a locale identifier. @@ -139,7 +136,6 @@ impl LanguageIdentifier { /// use icu::locid::LanguageIdentifier; /// /// assert_eq!(LanguageIdentifier::default(), LanguageIdentifier::UND); - /// assert_eq!("und", LanguageIdentifier::UND.to_string()); /// ``` pub const UND: Self = Self { language: subtags::Language::UND, @@ -159,13 +155,13 @@ impl LanguageIdentifier { /// use icu::locid::LanguageIdentifier; /// /// assert_eq!( - /// LanguageIdentifier::canonicalize("pL_latn_pl"), - /// Ok("pl-Latn-PL".to_string()) + /// LanguageIdentifier::canonicalize("pL_latn_pl").as_deref(), + /// Ok("pl-Latn-PL") /// ); /// ``` pub fn canonicalize<S: AsRef<[u8]>>(input: S) -> Result<String, ParserError> { let lang_id = Self::try_from_bytes(input.as_ref())?; - Ok(lang_id.to_string()) + Ok(lang_id.write_to_string().into_owned()) } /// Compare this [`LanguageIdentifier`] with BCP-47 bytes. @@ -197,7 +193,6 @@ impl LanguageIdentifier { /// let b = ab[1]; /// assert!(a.cmp(b) == Ordering::Less); /// let a_langid = a.parse::<LanguageIdentifier>().unwrap(); - /// assert_eq!(a, a_langid.to_string()); /// assert!(a_langid.strict_cmp(a.as_bytes()) == Ordering::Equal); /// assert!(a_langid.strict_cmp(b.as_bytes()) == Ordering::Less); /// } @@ -293,7 +288,7 @@ impl LanguageIdentifier { }; } - let mut iter = get_subtag_iterator(other.as_bytes()); + let mut iter = SubtagIterator::new(other.as_bytes()); if !subtag_matches!(subtags::Language, iter, self.language) { return false; } @@ -359,7 +354,7 @@ impl FromStr for LanguageIdentifier { } } -impl_writeable_for_each_subtag_str_no_test!(LanguageIdentifier); +impl_writeable_for_each_subtag_str_no_test!(LanguageIdentifier, selff, selff.script.is_none() && selff.region.is_none() && selff.variants.is_empty() => selff.language.write_to_string()); #[test] fn test_writeable() { @@ -387,14 +382,11 @@ fn test_writeable() { /// # Examples /// /// ``` -/// use icu::locid::subtags_language as language; -/// use icu::locid::LanguageIdentifier; -/// -/// let language = language!("en"); -/// let li = LanguageIdentifier::from(language); +/// use icu::locid::{ +/// langid, subtags_language as language, LanguageIdentifier, +/// }; /// -/// assert_eq!(li.language, language); -/// assert_eq!(li.to_string(), "en"); +/// assert_eq!(LanguageIdentifier::from(language!("en")), langid!("en")); /// ``` impl From<subtags::Language> for LanguageIdentifier { fn from(language: subtags::Language) -> Self { @@ -408,14 +400,12 @@ impl From<subtags::Language> for LanguageIdentifier { /// # Examples /// /// ``` -/// use icu::locid::subtags_script as script; -/// use icu::locid::LanguageIdentifier; +/// use icu::locid::{langid, subtags_script as script, LanguageIdentifier}; /// -/// let script = script!("latn"); -/// let li = LanguageIdentifier::from(Some(script)); -/// -/// assert_eq!(li.script.unwrap(), script); -/// assert_eq!(li.to_string(), "und-Latn"); +/// assert_eq!( +/// LanguageIdentifier::from(Some(script!("latn"))), +/// langid!("und-Latn") +/// ); /// ``` impl From<Option<subtags::Script>> for LanguageIdentifier { fn from(script: Option<subtags::Script>) -> Self { @@ -429,14 +419,12 @@ impl From<Option<subtags::Script>> for LanguageIdentifier { /// # Examples /// /// ``` -/// use icu::locid::subtags_region as region; -/// use icu::locid::LanguageIdentifier; +/// use icu::locid::{langid, subtags_region as region, LanguageIdentifier}; /// -/// let region = region!("US"); -/// let li = LanguageIdentifier::from(Some(region)); -/// -/// assert_eq!(li.region.unwrap(), region); -/// assert_eq!(li.to_string(), "und-US"); +/// assert_eq!( +/// LanguageIdentifier::from(Some(region!("US"))), +/// langid!("und-US") +/// ); /// ``` impl From<Option<subtags::Region>> for LanguageIdentifier { fn from(region: Option<subtags::Region>) -> Self { @@ -452,22 +440,18 @@ impl From<Option<subtags::Region>> for LanguageIdentifier { /// # Examples /// /// ``` -/// use icu::locid::LanguageIdentifier; /// use icu::locid::{ -/// subtags_language as language, subtags_region as region, -/// subtags_script as script, +/// langid, subtags_language as language, subtags_region as region, +/// subtags_script as script, LanguageIdentifier, /// }; /// /// let lang = language!("en"); /// let script = script!("Latn"); /// let region = region!("US"); -/// let li = LanguageIdentifier::from((lang, Some(script), Some(region))); -/// -/// assert_eq!(li.language, lang); -/// assert_eq!(li.script.unwrap(), script); -/// assert_eq!(li.region.unwrap(), region); -/// assert_eq!(li.variants.len(), 0); -/// assert_eq!(li.to_string(), "en-Latn-US"); +/// assert_eq!( +/// LanguageIdentifier::from((lang, Some(script), Some(region))), +/// langid!("en-Latn-US") +/// ); /// ``` impl From<( @@ -497,7 +481,6 @@ impl /// # Examples /// /// ``` -/// use icu::locid::LanguageIdentifier; /// use icu::locid::{ /// langid, subtags_language as language, subtags_region as region, /// subtags_script as script, diff --git a/vendor/icu_locid/src/lib.rs b/vendor/icu_locid/src/lib.rs index 885c4b743..226a8e53c 100644 --- a/vendor/icu_locid/src/lib.rs +++ b/vendor/icu_locid/src/lib.rs @@ -22,39 +22,23 @@ //! # Examples //! //! ``` -//! use icu::locid::subtags::{Language, Region}; //! use icu::locid::Locale; +//! use icu::locid::{ +//! locale, subtags_language as language, subtags_region as region, +//! }; //! -//! let mut loc: Locale = "en-US".parse().expect("Parsing failed."); -//! -//! let lang: Language = "en".parse().expect("Parsing failed."); -//! let region: Region = "US".parse().expect("Parsing failed."); +//! let mut loc: Locale = locale!("en-US"); //! -//! assert_eq!(loc.id.language, lang); +//! assert_eq!(loc.id.language, language!("en")); //! assert_eq!(loc.id.script, None); -//! assert_eq!(loc.id.region, Some(region)); +//! assert_eq!(loc.id.region, Some(region!("US"))); //! assert_eq!(loc.id.variants.len(), 0); //! -//! let region: Region = "GB".parse().expect("Parsing failed."); -//! loc.id.region = Some(region); +//! loc.id.region = Some(region!("GB")); //! -//! assert_eq!(loc.to_string(), "en-GB"); +//! assert_eq!(loc, locale!("en-GB")); //! ``` //! -//! ## Macros -//! -//! ```rust -//! use icu::locid::{ -//! langid, subtags_language as language, subtags_region as region, -//! }; -//! -//! let lid = langid!("EN_US"); -//! -//! assert_eq!(lid.language, language!("en")); -//! assert_eq!(lid.region, Some(region!("US"))); -//! ``` - -//! //! For more details, see [`Locale`] and [`LanguageIdentifier`]. //! //! [`UTS #35: Unicode LDML 3. Unicode Language and Locale Identifiers`]: https://unicode.org/reports/tr35/tr35.html#Unicode_Language_and_Locale_Identifiers diff --git a/vendor/icu_locid/src/locale.rs b/vendor/icu_locid/src/locale.rs index d7040d31a..5d9109fee 100644 --- a/vendor/icu_locid/src/locale.rs +++ b/vendor/icu_locid/src/locale.rs @@ -4,16 +4,15 @@ use crate::ordering::SubtagOrderingResult; use crate::parser::{ - get_subtag_iterator, parse_locale, - parse_locale_with_single_variant_single_keyword_unicode_keyword_extension, ParserError, - ParserMode, + parse_locale, parse_locale_with_single_variant_single_keyword_unicode_keyword_extension, + ParserError, ParserMode, SubtagIterator, }; use crate::{extensions, subtags, LanguageIdentifier}; use alloc::string::String; -use alloc::string::ToString; use core::cmp::Ordering; use core::str::FromStr; use tinystr::TinyAsciiStr; +use writeable::Writeable; /// A core struct representing a [`Unicode Locale Identifier`]. /// @@ -28,20 +27,21 @@ use tinystr::TinyAsciiStr; /// # Examples /// /// ``` -/// use icu::locid::extensions::unicode::{Key, Value}; -/// use icu::locid::{subtags::*, Locale}; +/// use icu_locid::{ +/// extensions_unicode_key as key, extensions_unicode_value as value, +/// locale, subtags_language as language, subtags_region as region, +/// }; /// -/// let loc: Locale = "en-US-u-ca-buddhist".parse().expect("Failed to parse."); +/// let loc = locale!("en-US-u-ca-buddhist"); /// -/// assert_eq!(loc.id.language, "en".parse::<Language>().unwrap()); +/// assert_eq!(loc.id.language, language!("en")); /// assert_eq!(loc.id.script, None); -/// assert_eq!(loc.id.region, "US".parse::<Region>().ok()); +/// assert_eq!(loc.id.region, Some(region!("US"))); /// assert_eq!(loc.id.variants.len(), 0); -/// assert_eq!(loc.to_string(), "en-US-u-ca-buddhist"); -/// -/// let key: Key = "ca".parse().expect("Parsing key failed."); -/// let value: Value = "buddhist".parse().expect("Parsing value failed."); -/// assert_eq!(loc.extensions.unicode.keywords.get(&key), Some(&value)); +/// assert_eq!( +/// loc.extensions.unicode.keywords.get(&key!("ca")), +/// Some(&value!("buddhist")) +/// ); /// ``` /// /// # Parsing @@ -87,6 +87,8 @@ pub struct Locale { #[test] fn test_sizes() { + // Remove when we upgrade to a compiler where the new sizes are default + let forced_nightly = std::env::var("ICU4X_BUILDING_WITH_FORCED_NIGHTLY").is_ok(); assert_eq!(core::mem::size_of::<subtags::Language>(), 3); assert_eq!(core::mem::size_of::<subtags::Script>(), 4); assert_eq!(core::mem::size_of::<subtags::Region>(), 3); @@ -99,12 +101,21 @@ fn test_sizes() { assert_eq!(core::mem::size_of::<extensions::transform::Fields>(), 24); assert_eq!(core::mem::size_of::<extensions::unicode::Attributes>(), 24); - assert_eq!(core::mem::size_of::<extensions::unicode::Keywords>(), 48); + assert_eq!( + core::mem::size_of::<extensions::unicode::Keywords>(), + if forced_nightly { 40 } else { 48 } + ); assert_eq!(core::mem::size_of::<Vec<extensions::other::Other>>(), 24); assert_eq!(core::mem::size_of::<extensions::private::Private>(), 24); - assert_eq!(core::mem::size_of::<extensions::Extensions>(), 192); + assert_eq!( + core::mem::size_of::<extensions::Extensions>(), + if forced_nightly { 184 } else { 192 } + ); - assert_eq!(core::mem::size_of::<Locale>(), 240); + assert_eq!( + core::mem::size_of::<Locale>(), + if forced_nightly { 232 } else { 240 } + ); } impl Locale { @@ -116,10 +127,7 @@ impl Locale { /// ``` /// use icu::locid::Locale; /// - /// let loc = Locale::try_from_bytes("en-US-u-hc-h12".as_bytes()) - /// .expect("Parsing failed."); - /// - /// assert_eq!(loc.to_string(), "en-US-u-hc-h12"); + /// Locale::try_from_bytes(b"en-US-u-hc-h12").unwrap(); /// ``` pub fn try_from_bytes(v: &[u8]) -> Result<Self, ParserError> { parse_locale(v) @@ -133,7 +141,6 @@ impl Locale { /// use icu::locid::Locale; /// /// assert_eq!(Locale::default(), Locale::UND); - /// assert_eq!("und", Locale::UND.to_string()); /// ``` pub const UND: Self = Self { id: LanguageIdentifier::UND, @@ -151,13 +158,13 @@ impl Locale { /// use icu::locid::Locale; /// /// assert_eq!( - /// Locale::canonicalize("pL_latn_pl-U-HC-H12"), - /// Ok("pl-Latn-PL-u-hc-h12".to_string()) + /// Locale::canonicalize("pL_latn_pl-U-HC-H12").as_deref(), + /// Ok("pl-Latn-PL-u-hc-h12") /// ); /// ``` pub fn canonicalize<S: AsRef<[u8]>>(input: S) -> Result<String, ParserError> { let locale = Self::try_from_bytes(input.as_ref())?; - Ok(locale.to_string()) + Ok(locale.write_to_string().into_owned()) } /// Compare this [`Locale`] with BCP-47 bytes. @@ -189,7 +196,6 @@ impl Locale { /// let b = ab[1]; /// assert!(a.cmp(b) == Ordering::Less); /// let a_loc = a.parse::<Locale>().unwrap(); - /// assert_eq!(a, a_loc.to_string()); /// assert!(a_loc.strict_cmp(a.as_bytes()) == Ordering::Equal); /// assert!(a_loc.strict_cmp(b.as_bytes()) == Ordering::Less); /// } @@ -286,7 +292,7 @@ impl Locale { }; } - let mut iter = get_subtag_iterator(other.as_bytes()); + let mut iter = SubtagIterator::new(other.as_bytes()); if !subtag_matches!(subtags::Language, iter, self.id.language) { return false; } @@ -391,7 +397,7 @@ impl core::fmt::Debug for Locale { } } -impl_writeable_for_each_subtag_str_no_test!(Locale); +impl_writeable_for_each_subtag_str_no_test!(Locale, selff, selff.extensions.is_empty() => selff.id.write_to_string()); #[test] fn test_writeable() { @@ -426,14 +432,10 @@ fn test_writeable() { /// # Examples /// /// ``` -/// use icu::locid::subtags_language as language; /// use icu::locid::Locale; +/// use icu::locid::{locale, subtags_language as language}; /// -/// let language = language!("en"); -/// let loc = Locale::from(language); -/// -/// assert_eq!(loc.id.language, language); -/// assert_eq!(loc.to_string(), "en"); +/// assert_eq!(Locale::from(language!("en")), locale!("en")); /// ``` impl From<subtags::Language> for Locale { fn from(language: subtags::Language) -> Self { @@ -447,14 +449,10 @@ impl From<subtags::Language> for Locale { /// # Examples /// /// ``` -/// use icu::locid::subtags_script as script; /// use icu::locid::Locale; +/// use icu::locid::{locale, subtags_script as script}; /// -/// let script = script!("latn"); -/// let loc = Locale::from(Some(script)); -/// -/// assert_eq!(loc.id.script.unwrap(), script); -/// assert_eq!(loc.to_string(), "und-Latn"); +/// assert_eq!(Locale::from(Some(script!("latn"))), locale!("und-Latn")); /// ``` impl From<Option<subtags::Script>> for Locale { fn from(script: Option<subtags::Script>) -> Self { @@ -468,14 +466,10 @@ impl From<Option<subtags::Script>> for Locale { /// # Examples /// /// ``` -/// use icu::locid::subtags_region as region; /// use icu::locid::Locale; +/// use icu::locid::{locale, subtags_region as region}; /// -/// let region = region!("US"); -/// let loc = Locale::from(Some(region)); -/// -/// assert_eq!(loc.id.region.unwrap(), region); -/// assert_eq!(loc.to_string(), "und-US"); +/// assert_eq!(Locale::from(Some(region!("US"))), locale!("und-US")); /// ``` impl From<Option<subtags::Region>> for Locale { fn from(region: Option<subtags::Region>) -> Self { @@ -491,20 +485,18 @@ impl From<Option<subtags::Region>> for Locale { /// ``` /// use icu::locid::Locale; /// use icu::locid::{ -/// subtags_language as language, subtags_region as region, +/// locale, subtags_language as language, subtags_region as region, /// subtags_script as script, /// }; /// -/// let lang = language!("en"); -/// let script = script!("Latn"); -/// let region = region!("US"); -/// let loc = Locale::from((lang, Some(script), Some(region))); -/// -/// assert_eq!(loc.id.language, lang); -/// assert_eq!(loc.id.script.unwrap(), script); -/// assert_eq!(loc.id.region.unwrap(), region); -/// assert_eq!(loc.id.variants.len(), 0); -/// assert_eq!(loc.to_string(), "en-Latn-US"); +/// assert_eq!( +/// Locale::from(( +/// language!("en"), +/// Some(script!("Latn")), +/// Some(region!("US")) +/// )), +/// locale!("en-Latn-US") +/// ); /// ``` impl From<( diff --git a/vendor/icu_locid/src/parser/errors.rs b/vendor/icu_locid/src/parser/errors.rs index a989bcc60..5cbbb2bd4 100644 --- a/vendor/icu_locid/src/parser/errors.rs +++ b/vendor/icu_locid/src/parser/errors.rs @@ -48,6 +48,22 @@ pub enum ParserError { /// ``` #[displaydoc("Invalid extension")] InvalidExtension, + + /// Duplicated extension. + /// + /// # Examples + /// + /// ``` + /// use icu::locid::Locale; + /// use icu::locid::ParserError; + /// + /// assert_eq!( + /// "und-u-hc-h12-u-ca-calendar".parse::<Locale>(), + /// Err(ParserError::DuplicatedExtension) + /// ); + /// ``` + #[displaydoc("Duplicated extension")] + DuplicatedExtension, } #[cfg(feature = "std")] diff --git a/vendor/icu_locid/src/parser/langid.rs b/vendor/icu_locid/src/parser/langid.rs index 9efa078ac..653ca7e6e 100644 --- a/vendor/icu_locid/src/parser/langid.rs +++ b/vendor/icu_locid/src/parser/langid.rs @@ -5,7 +5,7 @@ pub use super::errors::ParserError; use crate::extensions::unicode::{Attribute, Key, Value}; use crate::extensions::ExtensionType; -use crate::parser::{get_subtag_iterator, SubtagIterator}; +use crate::parser::SubtagIterator; use crate::LanguageIdentifier; use crate::{extensions, subtags}; use alloc::vec::Vec; @@ -103,7 +103,7 @@ pub fn parse_language_identifier( t: &[u8], mode: ParserMode, ) -> Result<LanguageIdentifier, ParserError> { - let mut iter = get_subtag_iterator(t); + let mut iter = SubtagIterator::new(t); parse_language_identifier_from_iter(&mut iter, mode) } @@ -127,9 +127,9 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f let mut variant = None; let mut keyword = None; - if let (i, Some((t, start, end))) = iter.next_manual() { + if let (i, Some((start, end))) = iter.next_manual() { iter = i; - match subtags::Language::try_from_bytes_manual_slice(t, start, end) { + match subtags::Language::try_from_bytes_manual_slice(iter.slice, start, end) { Ok(l) => language = l, Err(e) => return Err(e), } @@ -139,19 +139,23 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f let mut position = ParserPosition::Script; - while let Some((t, start, end)) = iter.peek_manual() { + while let Some((start, end)) = iter.peek_manual() { if !matches!(mode, ParserMode::LanguageIdentifier) && end - start == 1 { break; } if matches!(position, ParserPosition::Script) { - if let Ok(s) = subtags::Script::try_from_bytes_manual_slice(t, start, end) { + if let Ok(s) = subtags::Script::try_from_bytes_manual_slice(iter.slice, start, end) { script = Some(s); position = ParserPosition::Region; - } else if let Ok(r) = subtags::Region::try_from_bytes_manual_slice(t, start, end) { + } else if let Ok(r) = + subtags::Region::try_from_bytes_manual_slice(iter.slice, start, end) + { region = Some(r); position = ParserPosition::Variant; - } else if let Ok(v) = subtags::Variant::try_from_bytes_manual_slice(t, start, end) { + } else if let Ok(v) = + subtags::Variant::try_from_bytes_manual_slice(iter.slice, start, end) + { // We cannot handle multiple variants in a const context debug_assert!(variant.is_none()); variant = Some(v); @@ -162,10 +166,12 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f return Err(ParserError::InvalidSubtag); } } else if matches!(position, ParserPosition::Region) { - if let Ok(s) = subtags::Region::try_from_bytes_manual_slice(t, start, end) { + if let Ok(s) = subtags::Region::try_from_bytes_manual_slice(iter.slice, start, end) { region = Some(s); position = ParserPosition::Variant; - } else if let Ok(v) = subtags::Variant::try_from_bytes_manual_slice(t, start, end) { + } else if let Ok(v) = + subtags::Variant::try_from_bytes_manual_slice(iter.slice, start, end) + { // We cannot handle multiple variants in a const context debug_assert!(variant.is_none()); variant = Some(v); @@ -175,7 +181,8 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f } else { return Err(ParserError::InvalidSubtag); } - } else if let Ok(v) = subtags::Variant::try_from_bytes_manual_slice(t, start, end) { + } else if let Ok(v) = subtags::Variant::try_from_bytes_manual_slice(iter.slice, start, end) + { debug_assert!(matches!(position, ParserPosition::Variant)); if variant.is_some() { // We cannot handle multiple variants in a const context @@ -192,12 +199,12 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f } if matches!(mode, ParserMode::Locale) { - if let Some((bytes, start, end)) = iter.peek_manual() { - match ExtensionType::try_from_bytes_manual_slice(bytes, start, end) { + if let Some((start, end)) = iter.peek_manual() { + match ExtensionType::try_from_bytes_manual_slice(iter.slice, start, end) { Ok(ExtensionType::Unicode) => { iter = iter.next_manual().0; - if let Some((bytes, start, end)) = iter.peek_manual() { - if Attribute::try_from_bytes_manual_slice(bytes, start, end).is_ok() { + if let Some((start, end)) = iter.peek_manual() { + if Attribute::try_from_bytes_manual_slice(iter.slice, start, end).is_ok() { // We cannot handle Attributes in a const context return Err(ParserError::InvalidSubtag); } @@ -206,19 +213,21 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f let mut key = None; let mut current_type = None; - while let Some((bytes, start, end)) = iter.peek_manual() { + while let Some((start, end)) = iter.peek_manual() { let slen = end - start; if slen == 2 { if key.is_some() { // We cannot handle more than one Key in a const context return Err(ParserError::InvalidSubtag); } - match Key::try_from_bytes_manual_slice(bytes, start, end) { + match Key::try_from_bytes_manual_slice(iter.slice, start, end) { Ok(k) => key = Some(k), Err(e) => return Err(e), }; } else if key.is_some() { - match Value::parse_subtag_from_bytes_manual_slice(bytes, start, end) { + match Value::parse_subtag_from_bytes_manual_slice( + iter.slice, start, end, + ) { Ok(Some(t)) => { if current_type.is_some() { // We cannot handle more than one type in a const context @@ -261,7 +270,7 @@ pub const fn parse_language_identifier_with_single_variant( ), ParserError, > { - let iter = get_subtag_iterator(t); + let iter = SubtagIterator::new(t); match parse_locale_with_single_variant_single_keyword_unicode_extension_from_iter(iter, mode) { Ok((l, s, r, v, _)) => Ok((l, s, r, v)), Err(e) => Err(e), diff --git a/vendor/icu_locid/src/parser/locale.rs b/vendor/icu_locid/src/parser/locale.rs index 805b6c290..175fd3a05 100644 --- a/vendor/icu_locid/src/parser/locale.rs +++ b/vendor/icu_locid/src/parser/locale.rs @@ -6,13 +6,13 @@ use tinystr::TinyAsciiStr; use crate::extensions::{self, Extensions}; use crate::parser::errors::ParserError; -use crate::parser::{get_subtag_iterator, parse_language_identifier_from_iter, ParserMode}; +use crate::parser::{parse_language_identifier_from_iter, ParserMode, SubtagIterator}; use crate::{subtags, Locale}; use super::parse_locale_with_single_variant_single_keyword_unicode_extension_from_iter; pub fn parse_locale(t: &[u8]) -> Result<Locale, ParserError> { - let mut iter = get_subtag_iterator(t); + let mut iter = SubtagIterator::new(t); let id = parse_language_identifier_from_iter(&mut iter, ParserMode::Locale)?; let extensions = if iter.peek().is_some() { @@ -37,6 +37,6 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_keyword_ext ), ParserError, > { - let iter = get_subtag_iterator(t); + let iter = SubtagIterator::new(t); parse_locale_with_single_variant_single_keyword_unicode_extension_from_iter(iter, mode) } diff --git a/vendor/icu_locid/src/parser/mod.rs b/vendor/icu_locid/src/parser/mod.rs index fef10b0ab..4b02f71c9 100644 --- a/vendor/icu_locid/src/parser/mod.rs +++ b/vendor/icu_locid/src/parser/mod.rs @@ -17,72 +17,93 @@ pub use locale::{ parse_locale, parse_locale_with_single_variant_single_keyword_unicode_keyword_extension, }; -pub const fn get_subtag_iterator(slice: &[u8]) -> SubtagIterator { - let mut current_start = 0; +#[inline] +const fn is_separator(slice: &[u8], idx: usize) -> bool { #[allow(clippy::indexing_slicing)] - while current_start < slice.len() - && (slice[current_start] == b'-' || slice[current_start] == b'_') - { - current_start += 1; - } - let mut current_end = current_start; - #[allow(clippy::indexing_slicing)] - while current_end < slice.len() && slice[current_end] != b'-' && slice[current_end] != b'_' { - current_end += 1; - } - SubtagIterator { - slice, - current_start, - current_end, + let b = slice[idx]; + b == b'-' || b == b'_' +} + +const fn get_current_subtag(slice: &[u8], idx: usize) -> (usize, usize) { + debug_assert!(idx < slice.len()); + + // This function is called only on the idx == 0 or on a separator. + let (start, mut end) = if is_separator(slice, idx) { + // If it's a separator, set the start to idx+1 and advance the idx to the next char. + (idx + 1, idx + 1) + } else { + // If it's idx=0, start is 0 and end is set to 1 + debug_assert!(idx == 0); + (0, 1) + }; + + while end < slice.len() && !is_separator(slice, end) { + // Advance until we reach end of slice or a separator. + end += 1; } + // Notice: this slice may be empty (start == end) for cases like `"en-"` or `"en--US"` + (start, end) } +// `SubtagIterator` is a helper iterator for [`LanguageIdentifier`] and [`Locale`] parsing. +// +// It is quite extraordinary due to focus on performance and Rust limitations for `const` +// functions. +// +// The iterator is eager and fallible allowing it to reject invalid slices such as `"-"`, `"-en"`, +// `"en-"` etc. +// +// The iterator provides methods available for static users - `next_manual` and `peek_manual`, +// as well as typical `Peekable` iterator APIs - `next` and `peek`. +// +// All methods return an `Option` of a `Result`. #[derive(Copy, Clone, Debug)] pub struct SubtagIterator<'a> { - slice: &'a [u8], - current_start: usize, - current_end: usize, + pub slice: &'a [u8], + done: bool, + // done + subtag is faster than Option<(usize, usize)> + // at the time of writing. + subtag: (usize, usize), } -pub type ManualSlice<'a> = (&'a [u8], usize, usize); - impl<'a> SubtagIterator<'a> { - pub const fn next_manual(mut self) -> (Self, Option<ManualSlice<'a>>) { - if self.current_start == self.current_end { - (self, None) + pub const fn new(slice: &'a [u8]) -> Self { + let subtag = if slice.is_empty() || is_separator(slice, 0) { + // This returns (0, 0) which returns Some(b"") for slices like `"-en"` or `"-"` + (0, 0) } else { - let r = (self.slice, self.current_start, self.current_end); - self.current_start = self.current_end; - #[allow(clippy::indexing_slicing)] - while self.current_start < self.slice.len() - && (self.slice[self.current_start] == b'-' - || self.slice[self.current_start] == b'_') - { - self.current_start += 1; - } - self.current_end = self.current_start; - #[allow(clippy::indexing_slicing)] - while self.current_end < self.slice.len() - && self.slice[self.current_end] != b'-' - && self.slice[self.current_end] != b'_' - { - self.current_end += 1; - } - (self, Some(r)) + get_current_subtag(slice, 0) + }; + Self { + slice, + done: false, + subtag, } } - pub const fn peek_manual(&self) -> Option<ManualSlice<'a>> { - if self.current_start == self.current_end { - None + pub const fn next_manual(mut self) -> (Self, Option<(usize, usize)>) { + if self.done { + return (self, None); + } + let result = self.subtag; + if result.1 < self.slice.len() { + self.subtag = get_current_subtag(self.slice, result.1); } else { - Some((self.slice, self.current_start, self.current_end)) + self.done = true; } + (self, Some(result)) + } + + pub const fn peek_manual(&self) -> Option<(usize, usize)> { + if self.done { + return None; + } + Some(self.subtag) } pub fn peek(&self) -> Option<&'a [u8]> { #[allow(clippy::indexing_slicing)] // peek_manual returns valid indices - self.peek_manual().map(|(t, s, e)| &t[s..e]) + self.peek_manual().map(|(s, e)| &self.slice[s..e]) } } @@ -91,8 +112,120 @@ impl<'a> Iterator for SubtagIterator<'a> { fn next(&mut self) -> Option<Self::Item> { let (s, res) = self.next_manual(); - self.clone_from(&s); + *self = s; #[allow(clippy::indexing_slicing)] // next_manual returns valid indices - res.map(|(t, s, e)| &t[s..e]) + res.map(|(s, e)| &self.slice[s..e]) + } +} + +#[cfg(test)] +mod test { + use super::*; + + fn slice_to_str(input: &[u8]) -> &str { + std::str::from_utf8(input).unwrap() + } + + #[test] + fn subtag_iterator_peek_test() { + let slice = "de_at-u-ca-foobar"; + let mut si = SubtagIterator::new(slice.as_bytes()); + + assert_eq!(si.peek().map(slice_to_str), Some("de")); + assert_eq!(si.peek().map(slice_to_str), Some("de")); + assert_eq!(si.next().map(slice_to_str), Some("de")); + + assert_eq!(si.peek().map(slice_to_str), Some("at")); + assert_eq!(si.peek().map(slice_to_str), Some("at")); + assert_eq!(si.next().map(slice_to_str), Some("at")); + } + + #[test] + fn subtag_iterator_test() { + let slice = ""; + let mut si = SubtagIterator::new(slice.as_bytes()); + assert_eq!(si.next().map(slice_to_str), Some("")); + + let slice = "-"; + let mut si = SubtagIterator::new(slice.as_bytes()); + assert_eq!(si.next().map(slice_to_str), Some("")); + + let slice = "-en"; + let mut si = SubtagIterator::new(slice.as_bytes()); + assert_eq!(si.next().map(slice_to_str), Some("")); + assert_eq!(si.next().map(slice_to_str), Some("en")); + assert_eq!(si.next(), None); + + let slice = "en"; + let si = SubtagIterator::new(slice.as_bytes()); + assert_eq!(si.map(slice_to_str).collect::<Vec<_>>(), vec!["en",]); + + let slice = "en-"; + let si = SubtagIterator::new(slice.as_bytes()); + assert_eq!(si.map(slice_to_str).collect::<Vec<_>>(), vec!["en", "",]); + + let slice = "--"; + let mut si = SubtagIterator::new(slice.as_bytes()); + assert_eq!(si.next().map(slice_to_str), Some("")); + assert_eq!(si.next().map(slice_to_str), Some("")); + assert_eq!(si.next().map(slice_to_str), Some("")); + assert_eq!(si.next(), None); + + let slice = "-en-"; + let mut si = SubtagIterator::new(slice.as_bytes()); + assert_eq!(si.next().map(slice_to_str), Some("")); + assert_eq!(si.next().map(slice_to_str), Some("en")); + assert_eq!(si.next().map(slice_to_str), Some("")); + assert_eq!(si.next(), None); + + let slice = "de_at-u-ca-foobar"; + let si = SubtagIterator::new(slice.as_bytes()); + assert_eq!( + si.map(slice_to_str).collect::<Vec<_>>(), + vec!["de", "at", "u", "ca", "foobar",] + ); + } + + #[test] + fn get_current_subtag_test() { + let slice = "-"; + let current = get_current_subtag(slice.as_bytes(), 0); + assert_eq!(current, (1, 1)); + + let slice = "-en"; + let current = get_current_subtag(slice.as_bytes(), 0); + assert_eq!(current, (1, 3)); + + let slice = "-en-"; + let current = get_current_subtag(slice.as_bytes(), 3); + assert_eq!(current, (4, 4)); + + let slice = "en-"; + let current = get_current_subtag(slice.as_bytes(), 0); + assert_eq!(current, (0, 2)); + + let current = get_current_subtag(slice.as_bytes(), 2); + assert_eq!(current, (3, 3)); + + let slice = "en--US"; + let current = get_current_subtag(slice.as_bytes(), 0); + assert_eq!(current, (0, 2)); + + let current = get_current_subtag(slice.as_bytes(), 2); + assert_eq!(current, (3, 3)); + + let current = get_current_subtag(slice.as_bytes(), 3); + assert_eq!(current, (4, 6)); + + let slice = "--"; + let current = get_current_subtag(slice.as_bytes(), 0); + assert_eq!(current, (1, 1)); + + let current = get_current_subtag(slice.as_bytes(), 1); + assert_eq!(current, (2, 2)); + + let slice = "-"; + let current = get_current_subtag(slice.as_bytes(), 0); + assert_eq!(current, (1, 1)); } } diff --git a/vendor/icu_locid/src/subtags/language.rs b/vendor/icu_locid/src/subtags/language.rs index a5ec8d76e..86b51b93a 100644 --- a/vendor/icu_locid/src/subtags/language.rs +++ b/vendor/icu_locid/src/subtags/language.rs @@ -55,7 +55,6 @@ impl Language { /// use icu::locid::subtags::Language; /// /// assert_eq!(Language::default(), Language::UND); - /// assert_eq!("und", Language::UND.to_string()); /// ``` pub const UND: Self = unsafe { Self::from_raw_unchecked(*b"und") }; @@ -64,15 +63,15 @@ impl Language { /// # Examples /// /// ``` - /// use icu::locid::subtags::Language; + /// use icu::locid::{subtags::Language, subtags_language as language}; /// - /// let mut lang: Language = "csb".parse().expect("Parsing failed."); + /// let mut lang = language!("csb"); /// - /// assert_eq!(lang.as_str(), "csb"); + /// assert_ne!(lang, Language::UND); /// /// lang.clear(); /// - /// assert_eq!(lang.as_str(), "und"); + /// assert_eq!(lang, Language::UND); /// ``` #[inline] pub fn clear(&mut self) { @@ -86,7 +85,7 @@ impl Language { /// ``` /// use icu::locid::subtags::Language; /// - /// let mut lang: Language = "und".parse().expect("Parsing failed."); + /// let mut lang = Language::UND; /// /// assert!(lang.is_empty()); /// diff --git a/vendor/icu_locid/src/subtags/variants.rs b/vendor/icu_locid/src/subtags/variants.rs index bbff9ebac..3bd83f149 100644 --- a/vendor/icu_locid/src/subtags/variants.rs +++ b/vendor/icu_locid/src/subtags/variants.rs @@ -16,14 +16,9 @@ use core::ops::Deref; /// # Examples /// /// ``` -/// use icu::locid::subtags::{Variant, Variants}; +/// use icu::locid::{subtags::Variants, subtags_variant as variant}; /// -/// let variant1: Variant = -/// "posix".parse().expect("Failed to parse a variant subtag."); -/// -/// let variant2: Variant = -/// "macos".parse().expect("Failed to parse a variant subtag."); -/// let mut v = vec![variant1, variant2]; +/// let mut v = vec![variant!("posix"), variant!("macos")]; /// v.sort(); /// v.dedup(); /// @@ -53,10 +48,9 @@ impl Variants { /// # Examples /// /// ``` - /// use icu::locid::subtags::{Variant, Variants}; + /// use icu::locid::{subtags::Variants, subtags_variant as variant}; /// - /// let variant: Variant = "posix".parse().expect("Parsing failed."); - /// let variants = Variants::from_variant(variant); + /// let variants = Variants::from_variant(variant!("posix")); /// ``` #[inline] pub const fn from_variant(variant: Variant) -> Self { @@ -70,11 +64,9 @@ impl Variants { /// # Examples /// /// ``` - /// use icu::locid::subtags::{Variant, Variants}; + /// use icu::locid::{subtags::Variants, subtags_variant as variant}; /// - /// let variant1: Variant = "posix".parse().expect("Parsing failed."); - /// let variant2: Variant = "macos".parse().expect("Parsing failed."); - /// let mut v = vec![variant1, variant2]; + /// let mut v = vec![variant!("posix"), variant!("macos")]; /// v.sort(); /// v.dedup(); /// @@ -95,11 +87,9 @@ impl Variants { /// # Examples /// /// ``` - /// use icu::locid::subtags::{Variant, Variants}; + /// use icu::locid::{subtags::Variants, subtags_variant as variant}; /// - /// let variant1: Variant = "posix".parse().expect("Parsing failed."); - /// let variant2: Variant = "macos".parse().expect("Parsing failed."); - /// let mut v = vec![variant1, variant2]; + /// let mut v = vec![variant!("posix"), variant!("macos")]; /// v.sort(); /// v.dedup(); /// @@ -109,7 +99,7 @@ impl Variants { /// /// variants.clear(); /// - /// assert_eq!(variants.to_string(), ""); + /// assert_eq!(variants, Variants::default()); /// ``` pub fn clear(&mut self) -> Self { core::mem::take(self) |