diff --git a/components/calendar/src/any_calendar.rs b/components/calendar/src/any_calendar.rs index 92f8c9c13d5..884159dea07 100644 --- a/components/calendar/src/any_calendar.rs +++ b/components/calendar/src/any_calendar.rs @@ -1017,12 +1017,10 @@ impl AnyCalendarKind { AnyCalendarKind::Gregorian => value!("gregory"), AnyCalendarKind::Hebrew => value!("hebrew"), AnyCalendarKind::Indian => value!("indian"), - AnyCalendarKind::IslamicCivil => Value::try_from_bytes(b"islamic-civil").unwrap(), + AnyCalendarKind::IslamicCivil => Value::try_from_str("islamic-civil").unwrap(), AnyCalendarKind::IslamicObservational => value!("islamic"), - AnyCalendarKind::IslamicTabular => Value::try_from_bytes(b"islamic-tbla").unwrap(), - AnyCalendarKind::IslamicUmmAlQura => { - Value::try_from_bytes(b"islamic-umalqura").unwrap() - } + AnyCalendarKind::IslamicTabular => Value::try_from_str("islamic-tbla").unwrap(), + AnyCalendarKind::IslamicUmmAlQura => Value::try_from_str("islamic-umalqura").unwrap(), AnyCalendarKind::Iso => value!("iso"), AnyCalendarKind::Japanese => value!("japanese"), AnyCalendarKind::JapaneseExtended => value!("japanext"), diff --git a/components/datetime/README.md b/components/datetime/README.md index 217be6a6a26..72bf8d6dcf6 100644 --- a/components/datetime/README.md +++ b/components/datetime/README.md @@ -36,7 +36,6 @@ use icu::datetime::{ TypedDateTimeFormatter, }; use icu::locale::{locale, Locale}; -use std::str::FromStr; use writeable::assert_writeable_eq; // See the next code example for a more ergonomic example with .into(). @@ -47,7 +46,7 @@ let options = )); // You can work with a formatter that can select the calendar at runtime: -let locale = Locale::from_str("en-u-ca-gregory").unwrap(); +let locale = Locale::try_from_str("en-u-ca-gregory").unwrap(); let dtf = DateTimeFormatter::try_new(&locale.into(), options.clone()) .expect("Failed to create DateTimeFormatter instance."); diff --git a/components/datetime/src/any/zoned_datetime.rs b/components/datetime/src/any/zoned_datetime.rs index 6e289a69324..b4375025770 100644 --- a/components/datetime/src/any/zoned_datetime.rs +++ b/components/datetime/src/any/zoned_datetime.rs @@ -155,7 +155,6 @@ impl ZonedDateTimeFormatter { /// use icu::datetime::ZonedDateTimeFormatter; /// use icu::locale::locale; /// use icu::timezone::CustomTimeZone; - /// use std::str::FromStr; /// use writeable::assert_writeable_eq; /// /// let mut options = components::Bag::default(); @@ -174,7 +173,7 @@ impl ZonedDateTimeFormatter { /// /// let datetime = /// DateTime::try_new_iso_datetime(2021, 04, 08, 16, 12, 37).unwrap(); - /// let time_zone = CustomTimeZone::from_str("-07:00").unwrap(); + /// let time_zone = CustomTimeZone::try_from_str("-07:00").unwrap(); /// let any_datetime = datetime.to_any(); /// /// assert_writeable_eq!( @@ -330,7 +329,6 @@ impl ZonedDateTimeFormatter { /// use icu::datetime::ZonedDateTimeFormatter; /// use icu::locale::locale; /// use icu::timezone::CustomTimeZone; - /// use std::str::FromStr; /// use writeable::assert_writeable_eq; /// /// let options = length::Bag::from_date_time_style( @@ -348,7 +346,7 @@ impl ZonedDateTimeFormatter { /// /// let datetime = /// DateTime::try_new_iso_datetime(2021, 04, 08, 16, 12, 37).unwrap(); - /// let time_zone = CustomTimeZone::from_str("-07:00").unwrap(); + /// let time_zone = CustomTimeZone::try_from_str("-07:00").unwrap(); /// let any_datetime = datetime.to_any(); /// /// assert_writeable_eq!( @@ -576,7 +574,6 @@ fn buffer_constructor() { use icu::datetime::ZonedDateTimeFormatter; use icu::locale::locale; use icu::timezone::CustomTimeZone; - use std::str::FromStr; use writeable::assert_writeable_eq; let provider = icu_provider_blob::BlobDataProvider::try_new_from_static_blob(include_bytes!( @@ -597,7 +594,7 @@ fn buffer_constructor() { &DateTime::try_new_iso_datetime(2021, 04, 08, 16, 12, 37) .unwrap() .to_any(), - &CustomTimeZone::from_str("-07:00").unwrap() + &CustomTimeZone::try_from_str("-07:00").unwrap() ) .unwrap(), "Apr 8, 2021, 4:12:37 PM GMT-07:00" diff --git a/components/datetime/src/lib.rs b/components/datetime/src/lib.rs index b89953ae2e6..f4aee0b01c7 100644 --- a/components/datetime/src/lib.rs +++ b/components/datetime/src/lib.rs @@ -36,7 +36,6 @@ //! TypedDateTimeFormatter, //! }; //! use icu::locale::{locale, Locale}; -//! use std::str::FromStr; //! use writeable::assert_writeable_eq; //! //! // See the next code example for a more ergonomic example with .into(). @@ -47,7 +46,7 @@ //! )); //! //! // You can work with a formatter that can select the calendar at runtime: -//! let locale = Locale::from_str("en-u-ca-gregory").unwrap(); +//! let locale = Locale::try_from_str("en-u-ca-gregory").unwrap(); //! let dtf = DateTimeFormatter::try_new(&locale.into(), options.clone()) //! .expect("Failed to create DateTimeFormatter instance."); //! diff --git a/components/datetime/src/zoned_datetime.rs b/components/datetime/src/zoned_datetime.rs index e8ef4aebb90..3e8cb15fefc 100644 --- a/components/datetime/src/zoned_datetime.rs +++ b/components/datetime/src/zoned_datetime.rs @@ -54,7 +54,6 @@ use crate::{ /// use icu::datetime::{options::length, TypedZonedDateTimeFormatter}; /// use icu::locale::locale; /// use icu::timezone::CustomTimeZone; -/// use std::str::FromStr; /// use writeable::assert_writeable_eq; /// /// let options = length::Bag::from_date_time_style( @@ -70,7 +69,7 @@ use crate::{ /// /// let datetime = /// DateTime::try_new_gregorian_datetime(2020, 9, 12, 12, 34, 28).unwrap(); -/// let time_zone = CustomTimeZone::from_str("-07:00").unwrap(); +/// let time_zone = CustomTimeZone::try_from_str("-07:00").unwrap(); /// /// let formatted_date = zdtf.format(&datetime, &time_zone); /// @@ -368,7 +367,6 @@ impl TypedZonedDateTimeFormatter { /// use icu::datetime::{options::length, TypedZonedDateTimeFormatter}; /// use icu::locale::locale; /// use icu::timezone::CustomTimeZone; - /// use std::str::FromStr; /// use writeable::assert_writeable_eq; /// /// let options = length::Bag::from_date_time_style( @@ -385,7 +383,7 @@ impl TypedZonedDateTimeFormatter { /// /// let datetime = /// DateTime::try_new_gregorian_datetime(2020, 9, 12, 12, 34, 28).unwrap(); - /// let time_zone = CustomTimeZone::from_str("-07:00").unwrap(); + /// let time_zone = CustomTimeZone::try_from_str("-07:00").unwrap(); /// /// let formatted_date = zdtf.format(&datetime, &time_zone); /// @@ -409,7 +407,6 @@ impl TypedZonedDateTimeFormatter { /// use icu::datetime::{options::length, TypedZonedDateTimeFormatter}; /// use icu::locale::locale; /// use icu::timezone::CustomTimeZone; - /// use std::str::FromStr; /// /// let options = length::Bag::from_date_time_style( /// length::Date::Medium, @@ -425,7 +422,7 @@ impl TypedZonedDateTimeFormatter { /// /// let datetime = /// DateTime::try_new_gregorian_datetime(2020, 9, 12, 12, 34, 28).unwrap(); - /// let time_zone = CustomTimeZone::from_str("-07:00").unwrap(); + /// let time_zone = CustomTimeZone::try_from_str("-07:00").unwrap(); /// /// let formatted_string = zdtf.format_to_string(&datetime, &time_zone); /// diff --git a/components/datetime/tests/datetime.rs b/components/datetime/tests/datetime.rs index b7eb95bda90..c0c8a292b00 100644 --- a/components/datetime/tests/datetime.rs +++ b/components/datetime/tests/datetime.rs @@ -49,7 +49,6 @@ use patterns::{ dayperiods::{DayPeriodExpectation, DayPeriodTests}, time_zones::{TimeZoneConfig, TimeZoneExpectation, TimeZoneTests}, }; -use std::str::FromStr; use tinystr::tinystr; use writeable::assert_writeable_eq; @@ -98,7 +97,8 @@ fn test_fixture(fixture_name: &str, file: &str) { None => format!("\n file: {fixture_name}.json\n"), }; for (locale, output_value) in fx.output.values { - let locale = Locale::from_str(&locale).expect("Expected parseable locale in fixture"); + let locale = + Locale::try_from_str(&locale).expect("Expected parseable locale in fixture"); if let Some(kind) = AnyCalendarKind::get_for_locale(&locale) { match kind { AnyCalendarKind::Buddhist => assert_fixture_element( diff --git a/components/experimental/src/transliterate/transliterator/replaceable.rs b/components/experimental/src/transliterate/transliterator/replaceable.rs index 47dd438a56e..a756a27d34d 100644 --- a/components/experimental/src/transliterate/transliterator/replaceable.rs +++ b/components/experimental/src/transliterate/transliterator/replaceable.rs @@ -723,17 +723,17 @@ impl<'a, 'b> Insertable<'a, 'b> { /// Push a `&str` on the replacement. pub(crate) fn push_str(&mut self, s: &str) { // SAFETY: s is valid UTF-8 by type - unsafe { self.push_bytes(s.as_bytes()) }; + unsafe { self.push_utf8(s.as_bytes()) }; debug_assert!(self.curr <= self.end()); } /// # Safety - /// The caller must ensure that `bytes` is valid UTF-8. - unsafe fn push_bytes(&mut self, bytes: &[u8]) { - if self.free_range().len() >= bytes.len() { + /// The caller must ensure that `code_units` is valid UTF-8. + unsafe fn push_utf8(&mut self, code_units: &[u8]) { + if self.free_range().len() >= code_units.len() { // SAFETY: The caller guarantees these are valid UTF-8 - self._rep.content[self.curr..self.curr + bytes.len()].copy_from_slice(bytes); - self.curr += bytes.len(); + self._rep.content[self.curr..self.curr + code_units.len()].copy_from_slice(code_units); + self.curr += code_units.len(); return; } // eprintln!("WARNING: free space not sufficient for Insertable::push_bytes"); @@ -741,7 +741,7 @@ impl<'a, 'b> Insertable<'a, 'b> { // SAFETY: The caller guarantees these are valid UTF-8 self._rep .content - .splice(self.free_range(), bytes.iter().copied()); + .splice(self.free_range(), code_units.iter().copied()); // SAFETY: The free range did not have enough space. The above splice replaces the completey // remaining free range with the replacement, so there are no more un-replaced bytes left // in the replacement range. diff --git a/components/experimental/src/units/measureunit.rs b/components/experimental/src/units/measureunit.rs index 12e4c9870d9..8aecaaf2554 100644 --- a/components/experimental/src/units/measureunit.rs +++ b/components/experimental/src/units/measureunit.rs @@ -33,7 +33,7 @@ impl<'data> MeasureUnitParser<'data> { /// NOTE: /// if the unit id is found, the function will return (unit id, part without the unit id and without `-` at the beginning of the remaining part if it exists). /// if the unit id is not found, the function will return an error. - fn get_unit_id<'a>(&'a self, part: &'a [u8]) -> Result<(u16, &[u8]), InvalidUnitError> { + fn get_unit_id<'a>(&self, part: &'a [u8]) -> Result<(u16, &'a [u8]), InvalidUnitError> { let mut cursor = self.units_trie.cursor(); let mut longest_match = Err(InvalidUnitError); @@ -49,7 +49,7 @@ impl<'data> MeasureUnitParser<'data> { longest_match } - fn get_power<'a>(&'a self, part: &'a [u8]) -> Result<(u8, &[u8]), InvalidUnitError> { + fn get_power<'a>(&self, part: &'a [u8]) -> Result<(u8, &'a [u8]), InvalidUnitError> { let (power, part_without_power) = get_power(part); // If the power is not found, return the part as it is. @@ -67,7 +67,7 @@ impl<'data> MeasureUnitParser<'data> { /// Get the SI prefix. /// NOTE: /// if the prefix is not found, the function will return (SiPrefix { power: 0, base: Base::Decimal }, part). - fn get_si_prefix<'a>(&'a self, part: &'a [u8]) -> (SiPrefix, &[u8]) { + fn get_si_prefix<'a>(&self, part: &'a [u8]) -> (SiPrefix, &'a [u8]) { let (si_prefix, part_without_si_prefix) = get_si_prefix(part); if part_without_si_prefix.len() == part.len() { return (si_prefix, part); @@ -85,17 +85,22 @@ impl<'data> MeasureUnitParser<'data> { /// Returns: /// - Ok(MeasureUnit) if the identifier is valid. /// - Err(InvalidUnitError) if the identifier is invalid. - pub fn try_from_bytes(&self, identifier: &'data [u8]) -> Result { - if identifier.starts_with(b"-") || identifier.ends_with(b"-") { + #[inline] + pub fn try_from_str(&self, s: &str) -> Result { + self.try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(&self, mut code_units: &[u8]) -> Result { + if code_units.starts_with(b"-") || code_units.ends_with(b"-") { return Err(InvalidUnitError); } let mut measure_unit_items = Vec::::new(); - let mut identifier = identifier; let mut sign = 1; - while !identifier.is_empty() { + while !code_units.is_empty() { // First: extract the power. - let (power, identifier_part_without_power) = self.get_power(identifier)?; + let (power, identifier_part_without_power) = self.get_power(code_units)?; // Second: extract the si_prefix and the unit_id. let (si_prefix, unit_id, identifier_part_without_unit_id) = @@ -118,9 +123,9 @@ impl<'data> MeasureUnitParser<'data> { } // If the sign is negative, this means that the identifier may contain more than one `per-` keyword. Err(_) if sign == 1 => { - if let Some(remainder) = identifier.strip_prefix(b"per-") { + if let Some(remainder) = code_units.strip_prefix(b"per-") { sign = -1; - identifier = remainder; + code_units = remainder; continue; } @@ -138,7 +143,7 @@ impl<'data> MeasureUnitParser<'data> { unit_id, }); - identifier = match identifier_part_without_unit_id.strip_prefix(b"-") { + code_units = match identifier_part_without_unit_id.strip_prefix(b"-") { Some(remainder) => remainder, None if identifier_part_without_unit_id.is_empty() => { identifier_part_without_unit_id diff --git a/components/experimental/tests/units/units_test.rs b/components/experimental/tests/units/units_test.rs index dc381ea6259..da0b11b95a1 100644 --- a/components/experimental/tests/units/units_test.rs +++ b/components/experimental/tests/units/units_test.rs @@ -42,10 +42,10 @@ fn test_cldr_unit_tests() { for test in tests { let input_unit = parser - .try_from_bytes(test.input_unit.as_bytes()) + .try_from_str(&test.input_unit) .expect("Failed to parse input unit"); let output_unit = parser - .try_from_bytes(test.output_unit.as_bytes()) + .try_from_str(&test.output_unit) .expect("Failed to parse output unit"); let converter: UnitsConverter> = converter_factory @@ -211,10 +211,10 @@ fn test_units_non_convertible() { for (input, output) in non_convertible_units.iter() { let input_unit = parser - .try_from_bytes(input.as_bytes()) + .try_from_str(input) .expect("Failed to parse input unit"); let output_unit = parser - .try_from_bytes(output.as_bytes()) + .try_from_str(output) .expect("Failed to parse output unit"); let result: Option> = @@ -290,7 +290,7 @@ fn test_unparsable_units() { unparsable_units.iter().for_each(|unit| { assert!( - parser.try_from_bytes(unit.as_bytes()).is_err(), + parser.try_from_str(unit).is_err(), "Unit '{}' should be unparsable but was parsed successfully.", unit ); diff --git a/components/icu/examples/tui.rs b/components/icu/examples/tui.rs index 6f28b618f2b..f8f795d817f 100644 --- a/components/icu/examples/tui.rs +++ b/components/icu/examples/tui.rs @@ -15,7 +15,6 @@ use icu::plurals::{PluralCategory, PluralRules}; use icu::timezone::CustomTimeZone; use icu_collections::codepointinvlist::CodePointInversionListBuilder; use std::env; -use std::str::FromStr; fn print>(_input: T) { #[cfg(debug_assertions)] @@ -53,7 +52,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { ) .expect("Failed to create TypedDateTimeFormatter."); let today_date = DateTime::try_new_gregorian_datetime(2020, 10, 10, 18, 56, 0).unwrap(); - let today_tz = CustomTimeZone::from_str("Z").unwrap(); // Z refers to the utc timezone + let today_tz = CustomTimeZone::try_from_str("Z").unwrap(); // Z refers to the utc timezone let formatted_dt = dtf.format(&today_date, &today_tz); diff --git a/components/list/src/patterns.rs b/components/list/src/patterns.rs index bf06a69ef3e..15e6e84343b 100644 --- a/components/list/src/patterns.rs +++ b/components/list/src/patterns.rs @@ -18,18 +18,18 @@ impl<'data> ListFormatterPatternsV1<'data> { [start, middle, end, pair, short_start, short_middle, short_end, short_pair, narrow_start, narrow_middle, narrow_end, narrow_pair]: [&str; 12], ) -> Result { Ok(Self([ - ListJoinerPattern::from_str(start, true, false)?.into(), - ListJoinerPattern::from_str(middle, false, false)?.into(), - ListJoinerPattern::from_str(end, false, true)?.into(), - ListJoinerPattern::from_str(pair, true, true)?.into(), - ListJoinerPattern::from_str(short_start, true, false)?.into(), - ListJoinerPattern::from_str(short_middle, false, false)?.into(), - ListJoinerPattern::from_str(short_end, false, true)?.into(), - ListJoinerPattern::from_str(short_pair, true, true)?.into(), - ListJoinerPattern::from_str(narrow_start, true, false)?.into(), - ListJoinerPattern::from_str(narrow_middle, false, false)?.into(), - ListJoinerPattern::from_str(narrow_end, false, true)?.into(), - ListJoinerPattern::from_str(narrow_pair, true, true)?.into(), + ListJoinerPattern::try_from_str(start, true, false)?.into(), + ListJoinerPattern::try_from_str(middle, false, false)?.into(), + ListJoinerPattern::try_from_str(end, false, true)?.into(), + ListJoinerPattern::try_from_str(pair, true, true)?.into(), + ListJoinerPattern::try_from_str(short_start, true, false)?.into(), + ListJoinerPattern::try_from_str(short_middle, false, false)?.into(), + ListJoinerPattern::try_from_str(short_end, false, true)?.into(), + ListJoinerPattern::try_from_str(short_pair, true, true)?.into(), + ListJoinerPattern::try_from_str(narrow_start, true, false)?.into(), + ListJoinerPattern::try_from_str(narrow_middle, false, false)?.into(), + ListJoinerPattern::try_from_str(narrow_end, false, true)?.into(), + ListJoinerPattern::try_from_str(narrow_pair, true, true)?.into(), ])) } @@ -45,13 +45,13 @@ impl<'data> ListFormatterPatternsV1<'data> { regex: &SerdeDFA<'static>, alternative_pattern: &str, ) -> Result<(), DataError> { - let old = ListJoinerPattern::from_str(pattern, true, true)?; + let old = ListJoinerPattern::try_from_str(pattern, true, true)?; for i in 0..12 { #[allow(clippy::indexing_slicing)] // self.0 is &[_; 12] if self.0[i].default == old { self.0[i].special_case = Some(SpecialCasePattern { condition: regex.clone(), - pattern: ListJoinerPattern::from_str( + pattern: ListJoinerPattern::try_from_str( alternative_pattern, i % 4 == 0 || i % 4 == 3, // allow_prefix = start or pair i % 4 == 2 || i % 4 == 3, // allow_suffix = end or pair @@ -106,7 +106,11 @@ impl<'a> ConditionalListJoinerPattern<'a> { impl<'data> ListJoinerPattern<'data> { #[cfg(feature = "datagen")] - fn from_str(pattern: &str, allow_prefix: bool, allow_suffix: bool) -> Result { + fn try_from_str( + pattern: &str, + allow_prefix: bool, + allow_suffix: bool, + ) -> Result { match (pattern.find("{0}"), pattern.find("{1}")) { (Some(index_0), Some(index_1)) if index_0 < index_1 @@ -196,17 +200,17 @@ pub mod test { #[test] fn rejects_bad_patterns() { - assert!(ListJoinerPattern::from_str("{0} and", true, true).is_err()); - assert!(ListJoinerPattern::from_str("and {1}", true, true).is_err()); - assert!(ListJoinerPattern::from_str("{1} and {0}", true, true).is_err()); - assert!(ListJoinerPattern::from_str("{1{0}}", true, true).is_err()); - assert!(ListJoinerPattern::from_str("{0\u{202e}} and {1}", true, true).is_err()); - assert!(ListJoinerPattern::from_str("{{0}} {{1}}", true, true).is_ok()); + assert!(ListJoinerPattern::try_from_str("{0} and", true, true).is_err()); + assert!(ListJoinerPattern::try_from_str("and {1}", true, true).is_err()); + assert!(ListJoinerPattern::try_from_str("{1} and {0}", true, true).is_err()); + assert!(ListJoinerPattern::try_from_str("{1{0}}", true, true).is_err()); + assert!(ListJoinerPattern::try_from_str("{0\u{202e}} and {1}", true, true).is_err()); + assert!(ListJoinerPattern::try_from_str("{{0}} {{1}}", true, true).is_ok()); - assert!(ListJoinerPattern::from_str("{0} and {1} ", true, true).is_ok()); - assert!(ListJoinerPattern::from_str("{0} and {1} ", true, false).is_err()); - assert!(ListJoinerPattern::from_str(" {0} and {1}", true, true).is_ok()); - assert!(ListJoinerPattern::from_str(" {0} and {1}", false, true).is_err()); + assert!(ListJoinerPattern::try_from_str("{0} and {1} ", true, true).is_ok()); + assert!(ListJoinerPattern::try_from_str("{0} and {1} ", true, false).is_err()); + assert!(ListJoinerPattern::try_from_str(" {0} and {1}", true, true).is_ok()); + assert!(ListJoinerPattern::try_from_str(" {0} and {1}", false, true).is_err()); } #[test] diff --git a/components/locale_core/src/databake.rs b/components/locale_core/src/databake.rs index d7595444054..d2473b1f603 100644 --- a/components/locale_core/src/databake.rs +++ b/components/locale_core/src/databake.rs @@ -16,7 +16,7 @@ impl Bake for LanguageIdentifier { } } else { quote! { - icu_locale_core::LanguageIdentifier::from_str(#repr).unwrap() + icu_locale_core::LanguageIdentifier::try_from_str(#repr).unwrap() } } } diff --git a/components/locale_core/src/extensions/mod.rs b/components/locale_core/src/extensions/mod.rs index e423a2957e4..57221d86efe 100644 --- a/components/locale_core/src/extensions/mod.rs +++ b/components/locale_core/src/extensions/mod.rs @@ -96,8 +96,8 @@ impl ExtensionType { } } - pub(crate) const fn try_from_bytes_manual_slice( - bytes: &[u8], + pub(crate) const fn try_from_utf8_manual_slice( + code_units: &[u8], start: usize, end: usize, ) -> Result { @@ -105,7 +105,7 @@ impl ExtensionType { return Err(ParseError::InvalidExtension); } #[allow(clippy::indexing_slicing)] - Self::try_from_byte(bytes[start]) + Self::try_from_byte(code_units[start]) } } diff --git a/components/locale_core/src/extensions/other/mod.rs b/components/locale_core/src/extensions/other/mod.rs index 6fb0d5ea42f..d3cf09d3e22 100644 --- a/components/locale_core/src/extensions/other/mod.rs +++ b/components/locale_core/src/extensions/other/mod.rs @@ -56,6 +56,25 @@ pub struct Other { } impl Other { + /// A constructor which takes a str slice, parses it and + /// produces a well-formed [`Other`]. + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { + let mut iter = SubtagIterator::new(code_units); + + let ext = iter.next().ok_or(ParseError::InvalidExtension)?; + if let ExtensionType::Other(b) = ExtensionType::try_from_byte_slice(ext)? { + return Self::try_from_iter(b, &mut iter); + } + + Err(ParseError::InvalidExtension) + } + /// A constructor which takes a pre-sorted list of [`Subtag`]. /// /// # Panics @@ -83,17 +102,6 @@ impl Other { Self { ext, keys } } - pub(crate) fn try_from_bytes(t: &[u8]) -> Result { - let mut iter = SubtagIterator::new(t); - - let ext = iter.next().ok_or(ParseError::InvalidExtension)?; - if let ExtensionType::Other(b) = ExtensionType::try_from_byte_slice(ext)? { - return Self::try_from_iter(b, &mut iter); - } - - Err(ParseError::InvalidExtension) - } - pub(crate) fn try_from_iter(ext: u8, iter: &mut SubtagIterator) -> Result { debug_assert!(matches!( ExtensionType::try_from_byte(ext), @@ -105,7 +113,7 @@ impl Other { if !Subtag::valid_key(subtag) { break; } - if let Ok(key) = Subtag::try_from_bytes(subtag) { + if let Ok(key) = Subtag::try_from_utf8(subtag) { keys.push(key); } iter.next(); @@ -182,8 +190,9 @@ impl Other { impl FromStr for Other { type Err = ParseError; - fn from_str(source: &str) -> Result { - Self::try_from_bytes(source.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } diff --git a/components/locale_core/src/extensions/private/mod.rs b/components/locale_core/src/extensions/private/mod.rs index 33ada0906c9..0e686cbe9bb 100644 --- a/components/locale_core/src/extensions/private/mod.rs +++ b/components/locale_core/src/extensions/private/mod.rs @@ -82,6 +82,25 @@ impl Private { Self(ShortBoxSlice::new()) } + /// A constructor which takes a str slice, parses it and + /// produces a well-formed [`Private`]. + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { + let mut iter = SubtagIterator::new(code_units); + + let ext = iter.next().ok_or(ParseError::InvalidExtension)?; + if let ExtensionType::Private = ExtensionType::try_from_byte_slice(ext)? { + return Self::try_from_iter(&mut iter); + } + + Err(ParseError::InvalidExtension) + } + /// A constructor which takes a pre-sorted list of [`Subtag`]. /// /// # Examples @@ -115,17 +134,6 @@ impl Private { Self(ShortBoxSlice::new_single(input)) } - pub(crate) fn try_from_bytes(t: &[u8]) -> Result { - let mut iter = SubtagIterator::new(t); - - let ext = iter.next().ok_or(ParseError::InvalidExtension)?; - if let ExtensionType::Private = ExtensionType::try_from_byte_slice(ext)? { - return Self::try_from_iter(&mut iter); - } - - Err(ParseError::InvalidExtension) - } - /// Empties the [`Private`] list. /// /// # Examples @@ -149,7 +157,7 @@ impl Private { pub(crate) fn try_from_iter(iter: &mut SubtagIterator) -> Result { let keys = iter - .map(Subtag::try_from_bytes) + .map(Subtag::try_from_utf8) .collect::, _>>()?; if keys.is_empty() { @@ -176,8 +184,9 @@ impl Private { impl FromStr for Private { type Err = ParseError; - fn from_str(source: &str) -> Result { - Self::try_from_bytes(source.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } diff --git a/components/locale_core/src/extensions/transform/fields.rs b/components/locale_core/src/extensions/transform/fields.rs index f0602cede36..f672492ca30 100644 --- a/components/locale_core/src/extensions/transform/fields.rs +++ b/components/locale_core/src/extensions/transform/fields.rs @@ -57,7 +57,7 @@ impl Fields { /// use icu::locale::locale; /// use icu::locale::Locale; /// - /// let loc1 = Locale::try_from_bytes(b"und-t-h0-hybrid").unwrap(); + /// let loc1 = Locale::try_from_str("und-t-h0-hybrid").unwrap(); /// let loc2 = locale!("und-u-ca-buddhist"); /// /// assert!(!loc1.extensions.transform.fields.is_empty()); diff --git a/components/locale_core/src/extensions/transform/mod.rs b/components/locale_core/src/extensions/transform/mod.rs index 89cf25d49d1..b4541e7be02 100644 --- a/components/locale_core/src/extensions/transform/mod.rs +++ b/components/locale_core/src/extensions/transform/mod.rs @@ -107,6 +107,25 @@ impl Transform { } } + /// A constructor which takes a str slice, parses it and + /// produces a well-formed [`Transform`]. + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { + let mut iter = SubtagIterator::new(code_units); + + let ext = iter.next().ok_or(ParseError::InvalidExtension)?; + if let ExtensionType::Transform = ExtensionType::try_from_byte_slice(ext)? { + return Self::try_from_iter(&mut iter); + } + + Err(ParseError::InvalidExtension) + } + /// Returns `true` if there are no tfields and no tlang in the `TransformExtensionList`. /// /// # Examples @@ -122,17 +141,6 @@ impl Transform { self.lang.is_none() && self.fields.is_empty() } - pub(crate) fn try_from_bytes(t: &[u8]) -> Result { - let mut iter = SubtagIterator::new(t); - - let ext = iter.next().ok_or(ParseError::InvalidExtension)?; - if let ExtensionType::Transform = ExtensionType::try_from_byte_slice(ext)? { - return Self::try_from_iter(&mut iter); - } - - Err(ParseError::InvalidExtension) - } - /// Clears the transform extension, effectively removing it from the locale. /// /// # Examples @@ -179,7 +187,7 @@ impl Transform { let mut tfields = LiteMap::new(); if let Some(subtag) = iter.peek() { - if Language::try_from_bytes(subtag).is_ok() { + if Language::try_from_utf8(subtag).is_ok() { tlang = Some(parse_language_identifier_from_iter( iter, ParserMode::Partial, @@ -208,7 +216,7 @@ impl Transform { has_current_tvalue = false; continue; } - } else if let Ok(tkey) = Key::try_from_bytes(subtag) { + } else if let Ok(tkey) = Key::try_from_utf8(subtag) { current_tkey = Some(tkey); } else { break; @@ -254,8 +262,9 @@ impl Transform { impl FromStr for Transform { type Err = ParseError; - fn from_str(source: &str) -> Result { - Self::try_from_bytes(source.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } diff --git a/components/locale_core/src/extensions/transform/value.rs b/components/locale_core/src/extensions/transform/value.rs index 16e2a27c97b..4d5936937e1 100644 --- a/components/locale_core/src/extensions/transform/value.rs +++ b/components/locale_core/src/extensions/transform/value.rs @@ -33,7 +33,7 @@ const TYPE_LENGTH: RangeInclusive = 3..=8; const TRUE_TVALUE: Subtag = subtag!("true"); impl Value { - /// A constructor which takes a utf8 slice, parses it and + /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Value`]. /// /// # Examples @@ -41,18 +41,24 @@ impl Value { /// ``` /// use icu::locale::extensions::transform::Value; /// - /// let value = Value::try_from_bytes(b"hybrid").expect("Parsing failed."); + /// let value = Value::try_from_str("hybrid").expect("Parsing failed."); /// ``` - pub fn try_from_bytes(input: &[u8]) -> Result { + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut v = ShortBoxSlice::default(); let mut has_value = false; - for subtag in SubtagIterator::new(input) { + for subtag in SubtagIterator::new(code_units) { if !Self::is_type_subtag(subtag) { return Err(ParseError::InvalidExtension); } has_value = true; - let val = Subtag::try_from_bytes(subtag).map_err(|_| ParseError::InvalidExtension)?; + let val = Subtag::try_from_utf8(subtag).map_err(|_| ParseError::InvalidExtension)?; if val != TRUE_TVALUE { v.push(val); } @@ -76,7 +82,7 @@ impl Value { if !TYPE_LENGTH.contains(&t.len()) { return Err(ParseError::InvalidExtension); } - let s = Subtag::try_from_bytes(t).map_err(|_| ParseError::InvalidSubtag)?; + let s = Subtag::try_from_utf8(t).map_err(|_| ParseError::InvalidSubtag)?; let s = s.to_ascii_lowercase(); @@ -103,8 +109,9 @@ impl Value { impl FromStr for Value { type Err = ParseError; - fn from_str(source: &str) -> Result { - Self::try_from_bytes(source.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } @@ -130,7 +137,7 @@ fn test_writeable() { #[test] fn test_short_tvalue() { - let value = Value::from_str("foo-longstag"); + let value = Value::try_from_str("foo-longstag"); assert!(value.is_ok()); let value = value.unwrap(); assert_eq!(value.0.len(), 2); @@ -138,6 +145,6 @@ fn test_short_tvalue() { assert_eq!(s, reference); } - let value = Value::from_str("foo-ba"); + let value = Value::try_from_str("foo-ba"); assert!(value.is_err()); } diff --git a/components/locale_core/src/extensions/unicode/attributes.rs b/components/locale_core/src/extensions/unicode/attributes.rs index fe54cf66043..3ef583a7553 100644 --- a/components/locale_core/src/extensions/unicode/attributes.rs +++ b/components/locale_core/src/extensions/unicode/attributes.rs @@ -51,6 +51,19 @@ impl Attributes { Self(ShortBoxSlice::new()) } + /// A constructor which takes a str slice, parses it and + /// produces a well-formed [`Attributes`]. + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { + let mut iter = SubtagIterator::new(code_units); + Self::try_from_iter(&mut iter) + } + /// A constructor which takes a pre-sorted list of [`Attribute`] elements. /// /// @@ -75,11 +88,6 @@ impl Attributes { Self(input.into()) } - pub(crate) fn try_from_bytes(t: &[u8]) -> Result { - let mut iter = SubtagIterator::new(t); - Self::try_from_iter(&mut iter) - } - /// Empties the [`Attributes`] list. /// /// Returns the old list. @@ -109,7 +117,7 @@ impl Attributes { let mut attributes = ShortBoxSlice::new(); while let Some(subtag) = iter.peek() { - if let Ok(attr) = Attribute::try_from_bytes(subtag) { + if let Ok(attr) = Attribute::try_from_utf8(subtag) { if let Err(idx) = attributes.binary_search(&attr) { attributes.insert(idx, attr); } @@ -132,8 +140,9 @@ impl Attributes { impl FromStr for Attributes { type Err = ParseError; - fn from_str(source: &str) -> Result { - Self::try_from_bytes(source.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } diff --git a/components/locale_core/src/extensions/unicode/keywords.rs b/components/locale_core/src/extensions/unicode/keywords.rs index 22e6ed279de..fde29580667 100644 --- a/components/locale_core/src/extensions/unicode/keywords.rs +++ b/components/locale_core/src/extensions/unicode/keywords.rs @@ -91,8 +91,16 @@ impl Keywords { )) } - pub(crate) fn try_from_bytes(t: &[u8]) -> Result { - let mut iter = SubtagIterator::new(t); + /// A constructor which takes a str slice, parses it and + /// produces a well-formed [`Keywords`]. + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { + let mut iter = SubtagIterator::new(code_units); Self::try_from_iter(&mut iter) } @@ -104,7 +112,7 @@ impl Keywords { /// use icu::locale::locale; /// use icu::locale::Locale; /// - /// let loc1 = Locale::try_from_bytes(b"und-t-h0-hybrid").unwrap(); + /// let loc1 = Locale::try_from_str("und-t-h0-hybrid").unwrap(); /// let loc2 = locale!("und-u-ca-buddhist"); /// /// assert!(loc1.extensions.unicode.keywords.is_empty()); @@ -320,7 +328,7 @@ impl Keywords { keywords.try_insert(kw, Value::from_short_slice_unchecked(current_value)); current_value = ShortBoxSlice::new(); } - current_keyword = Some(Key::try_from_bytes(subtag)?); + current_keyword = Some(Key::try_from_utf8(subtag)?); } else if current_keyword.is_some() { match Value::parse_subtag(subtag) { Ok(Some(t)) => current_value.push(t), @@ -378,8 +386,9 @@ impl FromIterator<(Key, Value)> for Keywords { impl FromStr for Keywords { type Err = ParseError; - fn from_str(source: &str) -> Result { - Self::try_from_bytes(source.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } diff --git a/components/locale_core/src/extensions/unicode/mod.rs b/components/locale_core/src/extensions/unicode/mod.rs index 0f7fb92d8fe..3868ccd52d8 100644 --- a/components/locale_core/src/extensions/unicode/mod.rs +++ b/components/locale_core/src/extensions/unicode/mod.rs @@ -108,6 +108,25 @@ impl Unicode { } } + /// A constructor which takes a str slice, parses it and + /// produces a well-formed [`Unicode`]. + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { + let mut iter = SubtagIterator::new(code_units); + + let ext = iter.next().ok_or(ParseError::InvalidExtension)?; + if let ExtensionType::Unicode = ExtensionType::try_from_byte_slice(ext)? { + return Self::try_from_iter(&mut iter); + } + + Err(ParseError::InvalidExtension) + } + /// Returns [`true`] if there list of keywords and attributes is empty. /// /// # Examples @@ -123,17 +142,6 @@ impl Unicode { self.keywords.is_empty() && self.attributes.is_empty() } - pub(crate) fn try_from_bytes(t: &[u8]) -> Result { - let mut iter = SubtagIterator::new(t); - - let ext = iter.next().ok_or(ParseError::InvalidExtension)?; - if let ExtensionType::Unicode = ExtensionType::try_from_byte_slice(ext)? { - return Self::try_from_iter(&mut iter); - } - - Err(ParseError::InvalidExtension) - } - /// Clears all Unicode extension keywords and attributes, effectively removing /// the Unicode extension. /// @@ -199,8 +207,9 @@ impl Unicode { impl FromStr for Unicode { type Err = ParseError; - fn from_str(source: &str) -> Result { - Self::try_from_bytes(source.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } diff --git a/components/locale_core/src/extensions/unicode/subdivision.rs b/components/locale_core/src/extensions/unicode/subdivision.rs index 8d8f5a4de38..85c0a4c9d68 100644 --- a/components/locale_core/src/extensions/unicode/subdivision.rs +++ b/components/locale_core/src/extensions/unicode/subdivision.rs @@ -104,8 +104,16 @@ impl SubdivisionId { Self { region, suffix } } - pub(crate) fn try_from_bytes(input: &[u8]) -> Result { - let is_alpha = input + /// A constructor which takes a str slice, parses it and + /// produces a well-formed [`SubdivisionId`]. + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { + let is_alpha = code_units .first() .and_then(|b| { b.is_ascii_alphabetic() @@ -114,13 +122,13 @@ impl SubdivisionId { }) .ok_or(ParseError::InvalidExtension)?; let region_len = if is_alpha { 2 } else { 3 }; - if input.len() < region_len + 1 { + if code_units.len() < region_len + 1 { return Err(ParseError::InvalidExtension); } - let (region_bytes, suffix_bytes) = input.split_at(region_len); + let (region_code_units, suffix_code_units) = code_units.split_at(region_len); let region = - Region::try_from_bytes(region_bytes).map_err(|_| ParseError::InvalidExtension)?; - let suffix = SubdivisionSuffix::try_from_bytes(suffix_bytes)?; + Region::try_from_utf8(region_code_units).map_err(|_| ParseError::InvalidExtension)?; + let suffix = SubdivisionSuffix::try_from_utf8(suffix_code_units)?; Ok(Self { region, suffix }) } } @@ -143,8 +151,9 @@ writeable::impl_display_with_writeable!(SubdivisionId); impl FromStr for SubdivisionId { type Err = ParseError; + #[inline] fn from_str(s: &str) -> Result { - Self::try_from_bytes(s.as_bytes()) + Self::try_from_str(s) } } diff --git a/components/locale_core/src/extensions/unicode/value.rs b/components/locale_core/src/extensions/unicode/value.rs index 7497e163c9b..1ac15fb2607 100644 --- a/components/locale_core/src/extensions/unicode/value.rs +++ b/components/locale_core/src/extensions/unicode/value.rs @@ -38,7 +38,7 @@ pub struct Value(ShortBoxSlice); const TRUE_VALUE: Subtag = subtag!("true"); impl Value { - /// A constructor which takes a utf8 slice, parses it and + /// A constructor which str slice, parses it and /// produces a well-formed [`Value`]. /// /// # Examples @@ -46,14 +46,20 @@ impl Value { /// ``` /// use icu::locale::extensions::unicode::Value; /// - /// Value::try_from_bytes(b"buddhist").expect("Parsing failed."); + /// Value::try_from_str("buddhist").expect("Parsing failed."); /// ``` - pub fn try_from_bytes(input: &[u8]) -> Result { + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut v = ShortBoxSlice::new(); - if !input.is_empty() { - for chunk in SubtagIterator::new(input) { - let subtag = Subtag::try_from_bytes(chunk)?; + if !code_units.is_empty() { + for chunk in SubtagIterator::new(code_units) { + let subtag = Subtag::try_from_utf8(chunk)?; if subtag != TRUE_VALUE { v.push(subtag); } @@ -250,15 +256,15 @@ impl Value { } pub(crate) fn parse_subtag(t: &[u8]) -> Result, ParseError> { - Self::parse_subtag_from_bytes_manual_slice(t, 0, t.len()) + Self::parse_subtag_from_utf8_manual_slice(t, 0, t.len()) } - pub(crate) const fn parse_subtag_from_bytes_manual_slice( - bytes: &[u8], + pub(crate) const fn parse_subtag_from_utf8_manual_slice( + code_units: &[u8], start: usize, end: usize, ) -> Result, ParseError> { - match Subtag::try_from_bytes_manual_slice(bytes, start, end) { + match Subtag::try_from_utf8_manual_slice(code_units, start, end) { Ok(TRUE_VALUE) => Ok(None), Ok(s) => Ok(Some(s)), Err(_) => Err(ParseError::InvalidSubtag), @@ -300,8 +306,9 @@ impl Extend for Value { impl FromStr for Value { type Err = ParseError; - fn from_str(source: &str) -> Result { - Self::try_from_bytes(source.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } @@ -346,7 +353,7 @@ macro_rules! extensions_unicode_value { // Workaround until https://github.com/rust-lang/rust/issues/73255 lands: const R: $crate::extensions::unicode::Value = $crate::extensions::unicode::Value::from_subtag( - match $crate::subtags::Subtag::try_from_bytes($value.as_bytes()) { + match $crate::subtags::Subtag::try_from_utf8($value.as_bytes()) { Ok(r) => Some(r), _ => panic!(concat!("Invalid Unicode extension value: ", $value)), }, diff --git a/components/locale_core/src/helpers.rs b/components/locale_core/src/helpers.rs index dc1b3add80b..4ecd5eaf64d 100644 --- a/components/locale_core/src/helpers.rs +++ b/components/locale_core/src/helpers.rs @@ -25,7 +25,7 @@ macro_rules! impl_tinystr_subtag { pub struct $name(tinystr::TinyAsciiStr<$len_end>); impl $name { - /// A constructor which takes a UTF-8 slice, parses it and + /// A constructor which takes a str slice, parses it and #[doc = concat!("produces a well-formed [`", stringify!($name), "`].")] /// /// # Examples @@ -33,17 +33,24 @@ macro_rules! impl_tinystr_subtag { /// ``` #[doc = concat!("use icu_locale_core::", stringify!($($path::)+), stringify!($name), ";")] /// - #[doc = concat!("assert!(", stringify!($name), "::try_from_bytes(b", stringify!($good_example), ").is_ok());")] - #[doc = concat!("assert!(", stringify!($name), "::try_from_bytes(b", stringify!($bad_example), ").is_err());")] + #[doc = concat!("assert!(", stringify!($name), "::try_from_str(", stringify!($good_example), ").is_ok());")] + #[doc = concat!("assert!(", stringify!($name), "::try_from_str(", stringify!($bad_example), ").is_err());")] /// ``` - pub const fn try_from_bytes(v: &[u8]) -> Result { - Self::try_from_bytes_manual_slice(v, 0, v.len()) + #[inline] + pub const fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) } - /// Equivalent to [`try_from_bytes(bytes[start..end])`](Self::try_from_bytes), + /// See [`Self::try_from_str`] + #[inline] + pub const fn try_from_utf8(code_units: &[u8]) -> Result { + Self::try_from_utf8_manual_slice(code_units, 0, code_units.len()) + } + + /// Equivalent to [`try_from_utf8(bytes[start..end])`](Self::try_from_utf8), /// but callable in a `const` context (which range indexing is not). - pub const fn try_from_bytes_manual_slice( - v: &[u8], + pub const fn try_from_utf8_manual_slice( + code_units: &[u8], start: usize, end: usize, ) -> Result { @@ -54,19 +61,19 @@ macro_rules! impl_tinystr_subtag { return Err(crate::parser::errors::ParseError::$error); } - match tinystr::TinyAsciiStr::try_from_utf8_manual_slice(v, start, end) { + match tinystr::TinyAsciiStr::try_from_utf8_manual_slice(code_units, start, end) { Ok($tinystr_ident) if $validate => Ok(Self($normalize)), _ => Err(crate::parser::errors::ParseError::$error), } } #[doc = concat!("Safely creates a [`", stringify!($name), "`] from its raw format")] - /// as returned by [`Self::into_raw`]. Unlike [`Self::try_from_bytes`], + /// as returned by [`Self::into_raw`]. Unlike [`Self::try_from_utf8`], /// this constructor only takes normalized values. pub const fn try_from_raw( - v: [u8; $len_end], + raw: [u8; $len_end], ) -> Result { - if let Ok($tinystr_ident) = tinystr::TinyAsciiStr::<$len_end>::try_from_raw(v) { + if let Ok($tinystr_ident) = tinystr::TinyAsciiStr::<$len_end>::try_from_raw(raw) { if $tinystr_ident.len() >= $len_start && $is_normalized { Ok(Self($tinystr_ident)) } else { @@ -78,7 +85,7 @@ macro_rules! impl_tinystr_subtag { } #[doc = concat!("Unsafely creates a [`", stringify!($name), "`] from its raw format")] - /// as returned by [`Self::into_raw`]. Unlike [`Self::try_from_bytes`], + /// as returned by [`Self::into_raw`]. Unlike [`Self::try_from_utf8`], /// this constructor only takes normalized values. /// /// # Safety @@ -134,8 +141,9 @@ macro_rules! impl_tinystr_subtag { impl core::str::FromStr for $name { type Err = crate::parser::errors::ParseError; - fn from_str(source: &str) -> Result { - Self::try_from_bytes(source.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } @@ -192,7 +200,7 @@ macro_rules! impl_tinystr_subtag { ($string:literal) => {{ use $crate::$($path ::)+ $name; const R: $name = - match $name::try_from_bytes($string.as_bytes()) { + match $name::try_from_utf8($string.as_bytes()) { Ok(r) => r, #[allow(clippy::panic)] // const context _ => panic!(concat!("Invalid ", $(stringify!($path), "::",)+ stringify!($name), ": ", $string)), @@ -214,19 +222,19 @@ macro_rules! impl_tinystr_subtag { #[test] fn test_construction() { - let maybe = $name::try_from_bytes($good_example.as_bytes()); + let maybe = $name::try_from_utf8($good_example.as_bytes()); assert!(maybe.is_ok()); assert_eq!(maybe, $name::try_from_raw(maybe.unwrap().into_raw())); assert_eq!(maybe.unwrap().as_str(), $good_example); $( - let maybe = $name::try_from_bytes($more_good_examples.as_bytes()); + let maybe = $name::try_from_utf8($more_good_examples.as_bytes()); assert!(maybe.is_ok()); assert_eq!(maybe, $name::try_from_raw(maybe.unwrap().into_raw())); assert_eq!(maybe.unwrap().as_str(), $more_good_examples); )* - assert!($name::try_from_bytes($bad_example.as_bytes()).is_err()); + assert!($name::try_from_utf8($bad_example.as_bytes()).is_err()); $( - assert!($name::try_from_bytes($more_bad_examples.as_bytes()).is_err()); + assert!($name::try_from_utf8($more_bad_examples.as_bytes()).is_err()); )* } diff --git a/components/locale_core/src/langid.rs b/components/locale_core/src/langid.rs index 488ae2a01d3..fa349339546 100644 --- a/components/locale_core/src/langid.rs +++ b/components/locale_core/src/langid.rs @@ -84,18 +84,24 @@ impl LanguageIdentifier { /// ``` /// use icu::locale::LanguageIdentifier; /// - /// LanguageIdentifier::try_from_bytes(b"en-US").expect("Parsing failed"); + /// LanguageIdentifier::try_from_str("en-US").expect("Parsing failed"); /// ``` - pub fn try_from_bytes(v: &[u8]) -> Result { - parse_language_identifier(v, ParserMode::LanguageIdentifier) + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { + parse_language_identifier(code_units, ParserMode::LanguageIdentifier) } #[doc(hidden)] // macro use #[allow(clippy::type_complexity)] // The return type should be `Result` once the `const_precise_live_drops` // is stabilized ([rust-lang#73255](https://github.com/rust-lang/rust/issues/73255)). - pub const fn try_from_bytes_with_single_variant( - v: &[u8], + pub const fn try_from_utf8_with_single_variant( + code_units: &[u8], ) -> Result< ( subtags::Language, @@ -105,7 +111,7 @@ impl LanguageIdentifier { ), ParseError, > { - parse_language_identifier_with_single_variant(v, ParserMode::LanguageIdentifier) + parse_language_identifier_with_single_variant(code_units, ParserMode::LanguageIdentifier) } /// A constructor which takes a utf8 slice which may contain extension keys, @@ -168,7 +174,7 @@ impl LanguageIdentifier { /// ); /// ``` pub fn canonicalize>(input: S) -> Result { - let lang_id = Self::try_from_bytes(input.as_ref())?; + let lang_id = Self::try_from_utf8(input.as_ref())?; Ok(lang_id.write_to_string().into_owned()) } @@ -258,7 +264,7 @@ impl LanguageIdentifier { ($T:ty, $iter:ident, $expected:expr) => { $iter .next() - .map(|b| <$T>::try_from_bytes(b) == Ok($expected)) + .map(|b| <$T>::try_from_utf8(b) == Ok($expected)) .unwrap_or(false) }; } @@ -393,8 +399,9 @@ impl core::fmt::Debug for LanguageIdentifier { impl FromStr for LanguageIdentifier { type Err = ParseError; - fn from_str(source: &str) -> Result { - Self::try_from_bytes(source.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } diff --git a/components/locale_core/src/locale.rs b/components/locale_core/src/locale.rs index 6aa00d69127..ae67f228ce8 100644 --- a/components/locale_core/src/locale.rs +++ b/components/locale_core/src/locale.rs @@ -117,10 +117,16 @@ impl Locale { /// ``` /// use icu::locale::Locale; /// - /// Locale::try_from_bytes(b"en-US-u-hc-h12").unwrap(); + /// Locale::try_from_str("en-US-u-hc-h12").unwrap(); /// ``` - pub fn try_from_bytes(v: &[u8]) -> Result { - parse_locale(v) + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { + parse_locale(code_units) } /// The default undefined locale "und". Same as [`default()`](Default::default()). @@ -153,7 +159,7 @@ impl Locale { /// ); /// ``` pub fn canonicalize>(input: S) -> Result { - let locale = Self::try_from_bytes(input.as_ref())?; + let locale = Self::try_from_utf8(input.as_ref())?; Ok(locale.write_to_string().into_owned()) } @@ -263,7 +269,7 @@ impl Locale { ($T:ty, $iter:ident, $expected:expr) => { $iter .next() - .map(|b| <$T>::try_from_bytes(b) == Ok($expected)) + .map(|b| <$T>::try_from_utf8(b) == Ok($expected)) .unwrap_or(false) }; } @@ -304,8 +310,8 @@ impl Locale { #[doc(hidden)] // macro use #[allow(clippy::type_complexity)] - pub const fn try_from_bytes_with_single_variant_single_keyword_unicode_extension( - v: &[u8], + pub const fn try_from_utf8_with_single_variant_single_keyword_unicode_extension( + code_units: &[u8], ) -> Result< ( subtags::Language, @@ -317,7 +323,7 @@ impl Locale { ParseError, > { parse_locale_with_single_variant_single_keyword_unicode_keyword_extension( - v, + code_units, ParserMode::Locale, ) } @@ -335,8 +341,9 @@ impl Locale { impl FromStr for Locale { type Err = ParseError; - fn from_str(source: &str) -> Result { - Self::try_from_bytes(source.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } diff --git a/components/locale_core/src/macros.rs b/components/locale_core/src/macros.rs index 4d31e0b9121..202cdd434f2 100644 --- a/components/locale_core/src/macros.rs +++ b/components/locale_core/src/macros.rs @@ -38,7 +38,7 @@ macro_rules! langid { ($langid:literal) => {{ const R: $crate::LanguageIdentifier = - match $crate::LanguageIdentifier::try_from_bytes_with_single_variant($langid.as_bytes()) { + match $crate::LanguageIdentifier::try_from_utf8_with_single_variant($langid.as_bytes()) { Ok((language, script, region, variant)) => $crate::LanguageIdentifier { language, script, @@ -123,7 +123,7 @@ macro_rules! langid { macro_rules! locale { ($locale:literal) => {{ const R: $crate::Locale = - match $crate::Locale::try_from_bytes_with_single_variant_single_keyword_unicode_extension( + match $crate::Locale::try_from_utf8_with_single_variant_single_keyword_unicode_extension( $locale.as_bytes(), ) { Ok((language, script, region, variant, keyword)) => $crate::Locale { diff --git a/components/locale_core/src/parser/langid.rs b/components/locale_core/src/parser/langid.rs index 61ce68a1ba9..7a4bce53f84 100644 --- a/components/locale_core/src/parser/langid.rs +++ b/components/locale_core/src/parser/langid.rs @@ -34,7 +34,7 @@ pub fn parse_language_identifier_from_iter( let mut variants = ShortBoxSlice::new(); let language = if let Some(subtag) = iter.next() { - subtags::Language::try_from_bytes(subtag)? + subtags::Language::try_from_utf8(subtag)? } else { return Err(ParseError::InvalidLanguage); }; @@ -47,13 +47,13 @@ pub fn parse_language_identifier_from_iter( } if position == ParserPosition::Script { - if let Ok(s) = subtags::Script::try_from_bytes(subtag) { + if let Ok(s) = subtags::Script::try_from_utf8(subtag) { script = Some(s); position = ParserPosition::Region; - } else if let Ok(s) = subtags::Region::try_from_bytes(subtag) { + } else if let Ok(s) = subtags::Region::try_from_utf8(subtag) { region = Some(s); position = ParserPosition::Variant; - } else if let Ok(v) = subtags::Variant::try_from_bytes(subtag) { + } else if let Ok(v) = subtags::Variant::try_from_utf8(subtag) { if let Err(idx) = variants.binary_search(&v) { variants.insert(idx, v); } @@ -64,10 +64,10 @@ pub fn parse_language_identifier_from_iter( return Err(ParseError::InvalidSubtag); } } else if position == ParserPosition::Region { - if let Ok(s) = subtags::Region::try_from_bytes(subtag) { + if let Ok(s) = subtags::Region::try_from_utf8(subtag) { region = Some(s); position = ParserPosition::Variant; - } else if let Ok(v) = subtags::Variant::try_from_bytes(subtag) { + } else if let Ok(v) = subtags::Variant::try_from_utf8(subtag) { if let Err(idx) = variants.binary_search(&v) { variants.insert(idx, v); } @@ -77,7 +77,7 @@ pub fn parse_language_identifier_from_iter( } else { return Err(ParseError::InvalidSubtag); } - } else if let Ok(v) = subtags::Variant::try_from_bytes(subtag) { + } else if let Ok(v) = subtags::Variant::try_from_utf8(subtag) { if let Err(idx) = variants.binary_search(&v) { variants.insert(idx, v); } else { @@ -129,7 +129,7 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f if let (i, Some((start, end))) = iter.next_manual() { iter = i; - match subtags::Language::try_from_bytes_manual_slice(iter.slice, start, end) { + match subtags::Language::try_from_utf8_manual_slice(iter.slice, start, end) { Ok(l) => language = l, Err(e) => return Err(e), } @@ -145,16 +145,16 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f } if matches!(position, ParserPosition::Script) { - if let Ok(s) = subtags::Script::try_from_bytes_manual_slice(iter.slice, start, end) { + if let Ok(s) = subtags::Script::try_from_utf8_manual_slice(iter.slice, start, end) { script = Some(s); position = ParserPosition::Region; } else if let Ok(r) = - subtags::Region::try_from_bytes_manual_slice(iter.slice, start, end) + subtags::Region::try_from_utf8_manual_slice(iter.slice, start, end) { region = Some(r); position = ParserPosition::Variant; } else if let Ok(v) = - subtags::Variant::try_from_bytes_manual_slice(iter.slice, start, end) + subtags::Variant::try_from_utf8_manual_slice(iter.slice, start, end) { // We cannot handle multiple variants in a const context debug_assert!(variant.is_none()); @@ -166,11 +166,11 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f return Err(ParseError::InvalidSubtag); } } else if matches!(position, ParserPosition::Region) { - if let Ok(s) = subtags::Region::try_from_bytes_manual_slice(iter.slice, start, end) { + if let Ok(s) = subtags::Region::try_from_utf8_manual_slice(iter.slice, start, end) { region = Some(s); position = ParserPosition::Variant; } else if let Ok(v) = - subtags::Variant::try_from_bytes_manual_slice(iter.slice, start, end) + subtags::Variant::try_from_utf8_manual_slice(iter.slice, start, end) { // We cannot handle multiple variants in a const context debug_assert!(variant.is_none()); @@ -181,8 +181,7 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f } else { return Err(ParseError::InvalidSubtag); } - } else if let Ok(v) = subtags::Variant::try_from_bytes_manual_slice(iter.slice, start, end) - { + } else if let Ok(v) = subtags::Variant::try_from_utf8_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 @@ -200,11 +199,11 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f if matches!(mode, ParserMode::Locale) { if let Some((start, end)) = iter.peek_manual() { - match ExtensionType::try_from_bytes_manual_slice(iter.slice, start, end) { + match ExtensionType::try_from_utf8_manual_slice(iter.slice, start, end) { Ok(ExtensionType::Unicode) => { iter = iter.next_manual().0; if let Some((start, end)) = iter.peek_manual() { - if Attribute::try_from_bytes_manual_slice(iter.slice, start, end).is_ok() { + if Attribute::try_from_utf8_manual_slice(iter.slice, start, end).is_ok() { // We cannot handle Attributes in a const context return Err(ParseError::InvalidSubtag); } @@ -220,14 +219,13 @@ pub const fn parse_locale_with_single_variant_single_keyword_unicode_extension_f // We cannot handle more than one Key in a const context return Err(ParseError::InvalidSubtag); } - match Key::try_from_bytes_manual_slice(iter.slice, start, end) { + match Key::try_from_utf8_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( - iter.slice, start, end, - ) { + match Value::parse_subtag_from_utf8_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 diff --git a/components/locale_core/src/subtags/mod.rs b/components/locale_core/src/subtags/mod.rs index d79d54d24cd..b2f64c53671 100644 --- a/components/locale_core/src/subtags/mod.rs +++ b/components/locale_core/src/subtags/mod.rs @@ -129,7 +129,7 @@ impl TryFrom> for Subtag { type Error = crate::parser::errors::ParseError; fn try_from(value: tinystr::TinyAsciiStr) -> Result { - Self::try_from_bytes(value.as_bytes()) + Self::try_from_str(&value) } } diff --git a/components/locale_core/src/subtags/region.rs b/components/locale_core/src/subtags/region.rs index bb7e406f089..423d13603a9 100644 --- a/components/locale_core/src/subtags/region.rs +++ b/components/locale_core/src/subtags/region.rs @@ -50,11 +50,9 @@ impl Region { /// # Examples /// /// ``` - /// use icu::locale::subtags::Region; - /// - /// let region = Region::try_from_bytes(b"us").expect("Parsing failed."); + /// use icu::locale::subtags::region; /// - /// assert!(region.is_alphabetic()); + /// assert!(region!("us").is_alphabetic()); /// ``` pub fn is_alphabetic(&self) -> bool { self.0.len() == 2 diff --git a/components/locale_core/src/zerovec.rs b/components/locale_core/src/zerovec.rs index b17f7e8fa9b..2d7f7af904d 100644 --- a/components/locale_core/src/zerovec.rs +++ b/components/locale_core/src/zerovec.rs @@ -92,7 +92,7 @@ //! store a BCP-47 string and parse it when needed. //! //! Since the string is stored in an unparsed state, it is not safe to `unwrap` the result from -//! `Locale::try_from_bytes()`. See [icu4x#831](https://github.com/unicode-org/icu4x/issues/831) +//! `Locale::try_from_utf8()`. See [icu4x#831](https://github.com/unicode-org/icu4x/issues/831) //! for a discussion on potential data models that could ensure that the locale is valid during //! deserialization. //! @@ -117,12 +117,12 @@ //! //! // Construct a Locale by parsing the string. //! let value = zm.get(&25).expect("element is present"); -//! let loc = Locale::try_from_bytes(value); +//! let loc = Locale::try_from_utf8(value); //! assert_eq!(loc, Ok(langid!("zh-TW").into())); //! //! // Invalid entries are fallible //! let err_value = zm.get(&30).expect("element is present"); -//! let err_loc = Locale::try_from_bytes(err_value); +//! let err_loc = Locale::try_from_utf8(err_value); //! assert!(matches!(err_loc, Err(_))); //! ``` //! diff --git a/components/locale_core/tests/fixtures/mod.rs b/components/locale_core/tests/fixtures/mod.rs index cdd070bb2d5..1c0b48ba080 100644 --- a/components/locale_core/tests/fixtures/mod.rs +++ b/components/locale_core/tests/fixtures/mod.rs @@ -54,13 +54,10 @@ impl TryFrom for Extensions { .iter() .map(|(k, v)| { ( - unicode::Key::try_from_bytes(k.as_bytes()).expect("Parsing key failed."), + unicode::Key::try_from_str(k).expect("Parsing key failed."), v.as_ref().map_or( - unicode::Value::try_from_bytes(b"").expect("Failed to parse Value"), - |v| { - unicode::Value::try_from_bytes(v.as_bytes()) - .expect("Parsing type failed.") - }, + unicode::Value::try_from_str("").expect("Failed to parse Value"), + |v| unicode::Value::try_from_str(v).expect("Parsing type failed."), ), ) }) @@ -68,10 +65,7 @@ impl TryFrom for Extensions { let v: Vec = unicode .attributes .iter() - .map(|v| { - unicode::Attribute::try_from_bytes(v.as_bytes()) - .expect("Parsing attribute failed.") - }) + .map(|v| unicode::Attribute::try_from_str(v).expect("Parsing attribute failed.")) .collect(); ext.unicode.attributes = unicode::Attributes::from_vec_unchecked(v); } @@ -81,11 +75,10 @@ impl TryFrom for Extensions { .iter() .map(|(k, v)| { ( - transform::Key::try_from_bytes(k.as_bytes()).expect("Parsing key failed."), + transform::Key::try_from_str(k).expect("Parsing key failed."), v.as_ref() .map(|v| { - transform::Value::try_from_bytes(v.as_bytes()) - .expect("Parsing value failed.") + transform::Value::try_from_str(v).expect("Parsing value failed.") }) .expect("Value cannot be empty."), ) @@ -99,7 +92,7 @@ impl TryFrom for Extensions { let v: Vec = input .private .iter() - .map(|v| private::Subtag::try_from_bytes(v.as_bytes()).expect("Failed to add field.")) + .map(|v| private::Subtag::try_from_str(v).expect("Failed to add field.")) .collect(); ext.private = private::Private::from_vec_unchecked(v); Ok(ext) @@ -172,7 +165,7 @@ impl TryFrom for Locale { type Error = ParseError; fn try_from(input: LocaleIdentifier) -> Result { - Locale::try_from_bytes(input.identifier.as_bytes()) + Locale::try_from_str(&input.identifier) } } diff --git a/components/plurals/tests/categories.rs b/components/plurals/tests/categories.rs index 26fef7897b3..b36efbe75e4 100644 --- a/components/plurals/tests/categories.rs +++ b/components/plurals/tests/categories.rs @@ -6,7 +6,6 @@ mod fixtures; use icu_locale_core::LanguageIdentifier; use icu_plurals::{PluralCategory, PluralRules}; -use std::str::FromStr; #[test] fn test_categories() { @@ -16,7 +15,9 @@ fn test_categories() { for test in test_set { let pr = PluralRules::try_new( - &LanguageIdentifier::from_str(&test.langid).unwrap().into(), + &LanguageIdentifier::try_from_str(&test.langid) + .unwrap() + .into(), test.plural_type.into(), ) .unwrap(); diff --git a/components/timezone/src/provider.rs b/components/timezone/src/provider.rs index a4f9dafb449..d6c4b79cce7 100644 --- a/components/timezone/src/provider.rs +++ b/components/timezone/src/provider.rs @@ -72,7 +72,7 @@ pub struct TimeZoneBcp47Id(pub TinyAsciiStr<8>); impl FromStr for TimeZoneBcp47Id { type Err = tinystr::TinyStrError; fn from_str(s: &str) -> Result { - TinyAsciiStr::from_str(s).map(Into::into) + TinyAsciiStr::try_from_str(s).map(Into::into) } } @@ -145,7 +145,7 @@ impl From for TinyAsciiStr<4> { impl FromStr for MetazoneId { type Err = tinystr::TinyStrError; fn from_str(s: &str) -> Result { - TinyAsciiStr::from_str(s).map(Into::into) + TinyAsciiStr::try_from_str(s).map(Into::into) } } diff --git a/components/timezone/src/time_zone.rs b/components/timezone/src/time_zone.rs index 1371f22ac62..be42efd88c7 100644 --- a/components/timezone/src/time_zone.rs +++ b/components/timezone/src/time_zone.rs @@ -113,13 +113,13 @@ impl CustomTimeZone { /// use icu::timezone::CustomTimeZone; /// use icu::timezone::GmtOffset; /// - /// let tz0: CustomTimeZone = CustomTimeZone::try_from_bytes(b"Z") + /// let tz0: CustomTimeZone = CustomTimeZone::try_from_str("Z") /// .expect("Failed to parse a time zone"); - /// let tz1: CustomTimeZone = CustomTimeZone::try_from_bytes(b"+02") + /// let tz1: CustomTimeZone = CustomTimeZone::try_from_str("+02") /// .expect("Failed to parse a time zone"); - /// let tz2: CustomTimeZone = CustomTimeZone::try_from_bytes(b"-0230") + /// let tz2: CustomTimeZone = CustomTimeZone::try_from_str("-0230") /// .expect("Failed to parse a time zone"); - /// let tz3: CustomTimeZone = CustomTimeZone::try_from_bytes(b"+02:30") + /// let tz3: CustomTimeZone = CustomTimeZone::try_from_str("+02:30") /// .expect("Failed to parse a time zone"); /// /// assert_eq!(tz0.gmt_offset.map(GmtOffset::offset_seconds), Some(0)); @@ -127,8 +127,14 @@ impl CustomTimeZone { /// assert_eq!(tz2.gmt_offset.map(GmtOffset::offset_seconds), Some(-9000)); /// assert_eq!(tz3.gmt_offset.map(GmtOffset::offset_seconds), Some(9000)); /// ``` - pub fn try_from_bytes(bytes: &[u8]) -> Result { - let gmt_offset = GmtOffset::try_from_bytes(bytes)?; + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(code_units: &[u8]) -> Result { + let gmt_offset = GmtOffset::try_from_utf8(code_units)?; Ok(Self { gmt_offset: Some(gmt_offset), time_zone_id: None, @@ -177,37 +183,8 @@ impl CustomTimeZone { impl FromStr for CustomTimeZone { type Err = InvalidOffsetError; - /// Parse a [`CustomTimeZone`] from a string. - /// - /// This utility is for easily creating time zones, not a complete robust solution. - /// - /// The offset must range from GMT-12 to GMT+14. - /// The string must be an ISO-8601 time zone designator: - /// e.g. Z - /// e.g. +05 - /// e.g. +0500 - /// e.g. +05:00 - /// - /// # Examples - /// - /// ``` - /// use icu::timezone::CustomTimeZone; - /// use icu::timezone::GmtOffset; - /// - /// let tz0: CustomTimeZone = "Z".parse().expect("Failed to parse a time zone"); - /// let tz1: CustomTimeZone = - /// "+02".parse().expect("Failed to parse a time zone"); - /// let tz2: CustomTimeZone = - /// "-0230".parse().expect("Failed to parse a time zone"); - /// let tz3: CustomTimeZone = - /// "+02:30".parse().expect("Failed to parse a time zone"); - /// - /// assert_eq!(tz0.gmt_offset.map(GmtOffset::offset_seconds), Some(0)); - /// assert_eq!(tz1.gmt_offset.map(GmtOffset::offset_seconds), Some(7200)); - /// assert_eq!(tz2.gmt_offset.map(GmtOffset::offset_seconds), Some(-9000)); - /// assert_eq!(tz3.gmt_offset.map(GmtOffset::offset_seconds), Some(9000)); - /// ``` - fn from_str(input: &str) -> Result { - CustomTimeZone::try_from_bytes(input.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } diff --git a/components/timezone/src/types.rs b/components/timezone/src/types.rs index f1f764bd281..8a59958c10a 100644 --- a/components/timezone/src/types.rs +++ b/components/timezone/src/types.rs @@ -57,49 +57,55 @@ impl GmtOffset { /// use icu::timezone::GmtOffset; /// /// let offset0: GmtOffset = - /// GmtOffset::try_from_bytes(b"Z").expect("Failed to parse a time zone"); + /// GmtOffset::try_from_str("Z").expect("Failed to parse a time zone"); /// let offset1: GmtOffset = - /// GmtOffset::try_from_bytes(b"+05").expect("Failed to parse a time zone"); - /// let offset2: GmtOffset = GmtOffset::try_from_bytes(b"+0500") + /// GmtOffset::try_from_str("+05").expect("Failed to parse a time zone"); + /// let offset2: GmtOffset = GmtOffset::try_from_str("+0500") /// .expect("Failed to parse a time zone"); - /// let offset3: GmtOffset = GmtOffset::try_from_bytes(b"-05:00") + /// let offset3: GmtOffset = GmtOffset::try_from_str("-05:00") /// .expect("Failed to parse a time zone"); /// let offset_err0 = - /// GmtOffset::try_from_bytes(b"0500").expect_err("Invalid input"); + /// GmtOffset::try_from_str("0500").expect_err("Invalid input"); /// let offset_err1 = - /// GmtOffset::try_from_bytes(b"+05000").expect_err("Invalid input"); + /// GmtOffset::try_from_str("+05000").expect_err("Invalid input"); /// /// assert_eq!(offset0.offset_seconds(), 0); /// assert_eq!(offset1.offset_seconds(), 18000); /// assert_eq!(offset2.offset_seconds(), 18000); /// assert_eq!(offset3.offset_seconds(), -18000); /// ``` - pub fn try_from_bytes(mut chars: &[u8]) -> Result { - let offset_sign = match chars { + #[inline] + pub fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + + /// See [`Self::try_from_str`] + pub fn try_from_utf8(mut code_units: &[u8]) -> Result { + let offset_sign = match code_units { [b'+', rest @ ..] => { - chars = rest; + code_units = rest; 1 } [b'-', rest @ ..] => { - chars = rest; + code_units = rest; -1 } // Unicode minus ("\u{2212}" == [226, 136, 146]) [226, 136, 146, rest @ ..] => { - chars = rest; + code_units = rest; -1 } [b'Z'] => return Ok(Self(0)), _ => return Err(InvalidOffsetError), }; - let hours = match chars { + let hours = match code_units { &[h1, h2, ..] => try_get_time_component([h1, h2]), _ => None, } .ok_or(InvalidOffsetError)?; - let minutes = match chars { + let minutes = match code_units { /* ±hh */ &[_, _] => Some(0), /* ±hhmm, ±hh:mm */ @@ -152,30 +158,9 @@ impl GmtOffset { impl FromStr for GmtOffset { type Err = InvalidOffsetError; - /// Parse a [`GmtOffset`] from a string. - /// - /// The offset must range from GMT-12 to GMT+14. - /// The string must be an ISO 8601 time zone designator: - /// e.g. Z - /// e.g. +05 - /// e.g. +0500 - /// e.g. +05:00 - /// - /// # Examples - /// - /// ``` - /// use icu::timezone::GmtOffset; - /// - /// let offset0: GmtOffset = "Z".parse().expect("Failed to parse a GMT offset"); - /// let offset1: GmtOffset = - /// "-09".parse().expect("Failed to parse a GMT offset"); - /// let offset2: GmtOffset = - /// "-0930".parse().expect("Failed to parse a GMT offset"); - /// let offset3: GmtOffset = - /// "-09:30".parse().expect("Failed to parse a GMT offset"); - /// ``` - fn from_str(input: &str) -> Result { - GmtOffset::try_from_bytes(input.as_bytes()) + #[inline] + fn from_str(s: &str) -> Result { + Self::try_from_str(s) } } diff --git a/ffi/capi/bindings/c/ICU4XLocale.h b/ffi/capi/bindings/c/ICU4XLocale.h index ea99837cc6f..7c27216906c 100644 --- a/ffi/capi/bindings/c/ICU4XLocale.h +++ b/ffi/capi/bindings/c/ICU4XLocale.h @@ -26,21 +26,21 @@ ICU4XLocale* ICU4XLocale_clone(const ICU4XLocale* self); void ICU4XLocale_basename(const ICU4XLocale* self, DiplomatWrite* write); -diplomat_result_void_void ICU4XLocale_get_unicode_extension(const ICU4XLocale* self, const char* bytes_data, size_t bytes_len, DiplomatWrite* write); +diplomat_result_void_void ICU4XLocale_get_unicode_extension(const ICU4XLocale* self, const char* s_data, size_t s_len, DiplomatWrite* write); void ICU4XLocale_language(const ICU4XLocale* self, DiplomatWrite* write); -diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_language(ICU4XLocale* self, const char* bytes_data, size_t bytes_len); +diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_language(ICU4XLocale* self, const char* s_data, size_t s_len); diplomat_result_void_void ICU4XLocale_region(const ICU4XLocale* self, DiplomatWrite* write); -diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_region(ICU4XLocale* self, const char* bytes_data, size_t bytes_len); +diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_region(ICU4XLocale* self, const char* s_data, size_t s_len); diplomat_result_void_void ICU4XLocale_script(const ICU4XLocale* self, DiplomatWrite* write); -diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_script(ICU4XLocale* self, const char* bytes_data, size_t bytes_len); +diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_script(ICU4XLocale* self, const char* s_data, size_t s_len); -diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_canonicalize(const char* bytes_data, size_t bytes_len, DiplomatWrite* write); +diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_canonicalize(const char* s_data, size_t s_len, DiplomatWrite* write); void ICU4XLocale_to_string(const ICU4XLocale* self, DiplomatWrite* write); diff --git a/ffi/capi/bindings/cpp/ICU4XLocale.d.hpp b/ffi/capi/bindings/cpp/ICU4XLocale.d.hpp index 5e8c2ab2b79..76a6b274a1a 100644 --- a/ffi/capi/bindings/cpp/ICU4XLocale.d.hpp +++ b/ffi/capi/bindings/cpp/ICU4XLocale.d.hpp @@ -25,21 +25,21 @@ class ICU4XLocale { inline std::string basename() const; - inline std::optional get_unicode_extension(std::string_view bytes) const; + inline std::optional get_unicode_extension(std::string_view s) const; inline std::string language() const; - inline diplomat::result set_language(std::string_view bytes); + inline diplomat::result set_language(std::string_view s); inline std::optional region() const; - inline diplomat::result set_region(std::string_view bytes); + inline diplomat::result set_region(std::string_view s); inline std::optional script() const; - inline diplomat::result set_script(std::string_view bytes); + inline diplomat::result set_script(std::string_view s); - inline static diplomat::result canonicalize(std::string_view bytes); + inline static diplomat::result canonicalize(std::string_view s); inline std::string to_string() const; diff --git a/ffi/capi/bindings/cpp/ICU4XLocale.h b/ffi/capi/bindings/cpp/ICU4XLocale.h index ea99837cc6f..7c27216906c 100644 --- a/ffi/capi/bindings/cpp/ICU4XLocale.h +++ b/ffi/capi/bindings/cpp/ICU4XLocale.h @@ -26,21 +26,21 @@ ICU4XLocale* ICU4XLocale_clone(const ICU4XLocale* self); void ICU4XLocale_basename(const ICU4XLocale* self, DiplomatWrite* write); -diplomat_result_void_void ICU4XLocale_get_unicode_extension(const ICU4XLocale* self, const char* bytes_data, size_t bytes_len, DiplomatWrite* write); +diplomat_result_void_void ICU4XLocale_get_unicode_extension(const ICU4XLocale* self, const char* s_data, size_t s_len, DiplomatWrite* write); void ICU4XLocale_language(const ICU4XLocale* self, DiplomatWrite* write); -diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_language(ICU4XLocale* self, const char* bytes_data, size_t bytes_len); +diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_language(ICU4XLocale* self, const char* s_data, size_t s_len); diplomat_result_void_void ICU4XLocale_region(const ICU4XLocale* self, DiplomatWrite* write); -diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_region(ICU4XLocale* self, const char* bytes_data, size_t bytes_len); +diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_region(ICU4XLocale* self, const char* s_data, size_t s_len); diplomat_result_void_void ICU4XLocale_script(const ICU4XLocale* self, DiplomatWrite* write); -diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_script(ICU4XLocale* self, const char* bytes_data, size_t bytes_len); +diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_set_script(ICU4XLocale* self, const char* s_data, size_t s_len); -diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_canonicalize(const char* bytes_data, size_t bytes_len, DiplomatWrite* write); +diplomat_result_void_ICU4XLocaleParseError ICU4XLocale_canonicalize(const char* s_data, size_t s_len, DiplomatWrite* write); void ICU4XLocale_to_string(const ICU4XLocale* self, DiplomatWrite* write); diff --git a/ffi/capi/bindings/cpp/ICU4XLocale.hpp b/ffi/capi/bindings/cpp/ICU4XLocale.hpp index f08b6453790..2c0249e2492 100644 --- a/ffi/capi/bindings/cpp/ICU4XLocale.hpp +++ b/ffi/capi/bindings/cpp/ICU4XLocale.hpp @@ -38,12 +38,12 @@ inline std::string ICU4XLocale::basename() const { return output; } -inline std::optional ICU4XLocale::get_unicode_extension(std::string_view bytes) const { +inline std::optional ICU4XLocale::get_unicode_extension(std::string_view s) const { std::string output; capi::DiplomatWrite write = diplomat::WriteFromString(output); auto result = capi::ICU4XLocale_get_unicode_extension(this->AsFFI(), - bytes.data(), - bytes.size(), + s.data(), + s.size(), &write); return result.is_ok ? std::optional(std::move(output)) : std::nullopt; } @@ -56,10 +56,10 @@ inline std::string ICU4XLocale::language() const { return output; } -inline diplomat::result ICU4XLocale::set_language(std::string_view bytes) { +inline diplomat::result ICU4XLocale::set_language(std::string_view s) { auto result = capi::ICU4XLocale_set_language(this->AsFFI(), - bytes.data(), - bytes.size()); + s.data(), + s.size()); return result.is_ok ? diplomat::result(diplomat::Ok()) : diplomat::result(diplomat::Err(ICU4XLocaleParseError::FromFFI(result.err))); } @@ -71,10 +71,10 @@ inline std::optional ICU4XLocale::region() const { return result.is_ok ? std::optional(std::move(output)) : std::nullopt; } -inline diplomat::result ICU4XLocale::set_region(std::string_view bytes) { +inline diplomat::result ICU4XLocale::set_region(std::string_view s) { auto result = capi::ICU4XLocale_set_region(this->AsFFI(), - bytes.data(), - bytes.size()); + s.data(), + s.size()); return result.is_ok ? diplomat::result(diplomat::Ok()) : diplomat::result(diplomat::Err(ICU4XLocaleParseError::FromFFI(result.err))); } @@ -86,18 +86,18 @@ inline std::optional ICU4XLocale::script() const { return result.is_ok ? std::optional(std::move(output)) : std::nullopt; } -inline diplomat::result ICU4XLocale::set_script(std::string_view bytes) { +inline diplomat::result ICU4XLocale::set_script(std::string_view s) { auto result = capi::ICU4XLocale_set_script(this->AsFFI(), - bytes.data(), - bytes.size()); + s.data(), + s.size()); return result.is_ok ? diplomat::result(diplomat::Ok()) : diplomat::result(diplomat::Err(ICU4XLocaleParseError::FromFFI(result.err))); } -inline diplomat::result ICU4XLocale::canonicalize(std::string_view bytes) { +inline diplomat::result ICU4XLocale::canonicalize(std::string_view s) { std::string output; capi::DiplomatWrite write = diplomat::WriteFromString(output); - auto result = capi::ICU4XLocale_canonicalize(bytes.data(), - bytes.size(), + auto result = capi::ICU4XLocale_canonicalize(s.data(), + s.size(), &write); return result.is_ok ? diplomat::result(diplomat::Ok(std::move(output))) : diplomat::result(diplomat::Err(ICU4XLocaleParseError::FromFFI(result.err))); } diff --git a/ffi/capi/bindings/dart/CustomTimeZone.g.dart b/ffi/capi/bindings/dart/CustomTimeZone.g.dart index 3d7e9cc661c..35a06863958 100644 --- a/ffi/capi/bindings/dart/CustomTimeZone.g.dart +++ b/ffi/capi/bindings/dart/CustomTimeZone.g.dart @@ -24,7 +24,7 @@ final class CustomTimeZone implements ffi.Finalizable { /// Creates a time zone from an offset string. /// - /// See the [Rust documentation for `from_str`](https://docs.rs/icu/latest/icu/timezone/struct.CustomTimeZone.html#method.from_str) for more information. + /// See the [Rust documentation for `try_from_str`](https://docs.rs/icu/latest/icu/timezone/struct.CustomTimeZone.html#method.try_from_str) for more information. /// /// Throws [TimeZoneInvalidOffsetError] on failure. factory CustomTimeZone.fromString(String s) { diff --git a/ffi/capi/bindings/dart/Locale.g.dart b/ffi/capi/bindings/dart/Locale.g.dart index 0ecd232481b..5afa0bfa622 100644 --- a/ffi/capi/bindings/dart/Locale.g.dart +++ b/ffi/capi/bindings/dart/Locale.g.dart @@ -30,7 +30,7 @@ final class Locale implements ffi.Finalizable, core.Comparable { /// performance are critical and the locale is of a known shape (such as /// `aa-BB`) use `create_und`, `set_language`, `set_script`, and `set_region`. /// - /// See the [Rust documentation for `try_from_bytes`](https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_bytes) for more information. + /// See the [Rust documentation for `try_from_str`](https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_str) for more information. /// /// Throws [LocaleParseError] on failure. factory Locale.fromString(String name) { @@ -73,11 +73,11 @@ final class Locale implements ffi.Finalizable, core.Comparable { /// Returns a string representation of the unicode extension. /// /// See the [Rust documentation for `extensions`](https://docs.rs/icu/latest/icu/locale/struct.Locale.html#structfield.extensions) for more information. - String? getUnicodeExtension(String bytes) { + String? getUnicodeExtension(String s) { final temp = ffi2.Arena(); - final bytesView = bytes.utf8View; + final sView = s.utf8View; final write = _Write(); - final result = _ICU4XLocale_get_unicode_extension(_ffi, bytesView.allocIn(temp), bytesView.length, write._ffi); + final result = _ICU4XLocale_get_unicode_extension(_ffi, sView.allocIn(temp), sView.length, write._ffi); temp.releaseAll(); if (!result.isOk) { return null; @@ -96,13 +96,13 @@ final class Locale implements ffi.Finalizable, core.Comparable { /// Set the language part of the [`Locale`]. /// - /// See the [Rust documentation for `try_from_bytes`](https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_bytes) for more information. + /// See the [Rust documentation for `try_from_str`](https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_str) for more information. /// /// Throws [LocaleParseError] on failure. - set language(String bytes) { + set language(String s) { final temp = ffi2.Arena(); - final bytesView = bytes.utf8View; - final result = _ICU4XLocale_set_language(_ffi, bytesView.allocIn(temp), bytesView.length); + final sView = s.utf8View; + final result = _ICU4XLocale_set_language(_ffi, sView.allocIn(temp), sView.length); temp.releaseAll(); if (!result.isOk) { throw LocaleParseError.values[result.union.err]; @@ -124,13 +124,13 @@ final class Locale implements ffi.Finalizable, core.Comparable { /// Set the region part of the [`Locale`]. /// - /// See the [Rust documentation for `try_from_bytes`](https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_bytes) for more information. + /// See the [Rust documentation for `try_from_str`](https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_str) for more information. /// /// Throws [LocaleParseError] on failure. - void setRegion(String bytes) { + void setRegion(String s) { final temp = ffi2.Arena(); - final bytesView = bytes.utf8View; - final result = _ICU4XLocale_set_region(_ffi, bytesView.allocIn(temp), bytesView.length); + final sView = s.utf8View; + final result = _ICU4XLocale_set_region(_ffi, sView.allocIn(temp), sView.length); temp.releaseAll(); if (!result.isOk) { throw LocaleParseError.values[result.union.err]; @@ -152,13 +152,13 @@ final class Locale implements ffi.Finalizable, core.Comparable { /// Set the script part of the [`Locale`]. Pass an empty string to remove the script. /// - /// See the [Rust documentation for `try_from_bytes`](https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_bytes) for more information. + /// See the [Rust documentation for `try_from_str`](https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_str) for more information. /// /// Throws [LocaleParseError] on failure. - void setScript(String bytes) { + void setScript(String s) { final temp = ffi2.Arena(); - final bytesView = bytes.utf8View; - final result = _ICU4XLocale_set_script(_ffi, bytesView.allocIn(temp), bytesView.length); + final sView = s.utf8View; + final result = _ICU4XLocale_set_script(_ffi, sView.allocIn(temp), sView.length); temp.releaseAll(); if (!result.isOk) { throw LocaleParseError.values[result.union.err]; @@ -173,11 +173,11 @@ final class Locale implements ffi.Finalizable, core.Comparable { /// See the [Rust documentation for `canonicalize`](https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.canonicalize) for more information. /// /// Throws [LocaleParseError] on failure. - static String canonicalize(String bytes) { + static String canonicalize(String s) { final temp = ffi2.Arena(); - final bytesView = bytes.utf8View; + final sView = s.utf8View; final write = _Write(); - final result = _ICU4XLocale_canonicalize(bytesView.allocIn(temp), bytesView.length, write._ffi); + final result = _ICU4XLocale_canonicalize(sView.allocIn(temp), sView.length, write._ffi); temp.releaseAll(); if (!result.isOk) { throw LocaleParseError.values[result.union.err]; @@ -253,7 +253,7 @@ external void _ICU4XLocale_basename(ffi.Pointer self, ffi.Pointer, ffi.Pointer, ffi.Size, ffi.Pointer)>(isLeaf: true, symbol: 'ICU4XLocale_get_unicode_extension') // ignore: non_constant_identifier_names -external _ResultVoidVoid _ICU4XLocale_get_unicode_extension(ffi.Pointer self, ffi.Pointer bytesData, int bytesLength, ffi.Pointer write); +external _ResultVoidVoid _ICU4XLocale_get_unicode_extension(ffi.Pointer self, ffi.Pointer sData, int sLength, ffi.Pointer write); @meta.ResourceIdentifier('ICU4XLocale_language') @ffi.Native, ffi.Pointer)>(isLeaf: true, symbol: 'ICU4XLocale_language') @@ -263,7 +263,7 @@ external void _ICU4XLocale_language(ffi.Pointer self, ffi.Pointer, ffi.Pointer, ffi.Size)>(isLeaf: true, symbol: 'ICU4XLocale_set_language') // ignore: non_constant_identifier_names -external _ResultVoidInt32 _ICU4XLocale_set_language(ffi.Pointer self, ffi.Pointer bytesData, int bytesLength); +external _ResultVoidInt32 _ICU4XLocale_set_language(ffi.Pointer self, ffi.Pointer sData, int sLength); @meta.ResourceIdentifier('ICU4XLocale_region') @ffi.Native<_ResultVoidVoid Function(ffi.Pointer, ffi.Pointer)>(isLeaf: true, symbol: 'ICU4XLocale_region') @@ -273,7 +273,7 @@ external _ResultVoidVoid _ICU4XLocale_region(ffi.Pointer self, ffi.P @meta.ResourceIdentifier('ICU4XLocale_set_region') @ffi.Native<_ResultVoidInt32 Function(ffi.Pointer, ffi.Pointer, ffi.Size)>(isLeaf: true, symbol: 'ICU4XLocale_set_region') // ignore: non_constant_identifier_names -external _ResultVoidInt32 _ICU4XLocale_set_region(ffi.Pointer self, ffi.Pointer bytesData, int bytesLength); +external _ResultVoidInt32 _ICU4XLocale_set_region(ffi.Pointer self, ffi.Pointer sData, int sLength); @meta.ResourceIdentifier('ICU4XLocale_script') @ffi.Native<_ResultVoidVoid Function(ffi.Pointer, ffi.Pointer)>(isLeaf: true, symbol: 'ICU4XLocale_script') @@ -283,12 +283,12 @@ external _ResultVoidVoid _ICU4XLocale_script(ffi.Pointer self, ffi.P @meta.ResourceIdentifier('ICU4XLocale_set_script') @ffi.Native<_ResultVoidInt32 Function(ffi.Pointer, ffi.Pointer, ffi.Size)>(isLeaf: true, symbol: 'ICU4XLocale_set_script') // ignore: non_constant_identifier_names -external _ResultVoidInt32 _ICU4XLocale_set_script(ffi.Pointer self, ffi.Pointer bytesData, int bytesLength); +external _ResultVoidInt32 _ICU4XLocale_set_script(ffi.Pointer self, ffi.Pointer sData, int sLength); @meta.ResourceIdentifier('ICU4XLocale_canonicalize') @ffi.Native<_ResultVoidInt32 Function(ffi.Pointer, ffi.Size, ffi.Pointer)>(isLeaf: true, symbol: 'ICU4XLocale_canonicalize') // ignore: non_constant_identifier_names -external _ResultVoidInt32 _ICU4XLocale_canonicalize(ffi.Pointer bytesData, int bytesLength, ffi.Pointer write); +external _ResultVoidInt32 _ICU4XLocale_canonicalize(ffi.Pointer sData, int sLength, ffi.Pointer write); @meta.ResourceIdentifier('ICU4XLocale_to_string') @ffi.Native, ffi.Pointer)>(isLeaf: true, symbol: 'ICU4XLocale_to_string') diff --git a/ffi/capi/bindings/js/ICU4XCustomTimeZone.d.ts b/ffi/capi/bindings/js/ICU4XCustomTimeZone.d.ts index 18299a23316..e43734eddb5 100644 --- a/ffi/capi/bindings/js/ICU4XCustomTimeZone.d.ts +++ b/ffi/capi/bindings/js/ICU4XCustomTimeZone.d.ts @@ -16,7 +16,7 @@ export class ICU4XCustomTimeZone { * Creates a time zone from an offset string. - * See the {@link https://docs.rs/icu/latest/icu/timezone/struct.CustomTimeZone.html#method.from_str Rust documentation for `from_str`} for more information. + * See the {@link https://docs.rs/icu/latest/icu/timezone/struct.CustomTimeZone.html#method.try_from_str Rust documentation for `try_from_str`} for more information. * @throws {@link FFIError}<{@link ICU4XTimeZoneInvalidOffsetError}> */ static create_from_string(s: string): ICU4XCustomTimeZone | never; diff --git a/ffi/capi/bindings/js/ICU4XLocale.d.ts b/ffi/capi/bindings/js/ICU4XLocale.d.ts index 4b175a3ddb1..570fede7ab5 100644 --- a/ffi/capi/bindings/js/ICU4XLocale.d.ts +++ b/ffi/capi/bindings/js/ICU4XLocale.d.ts @@ -16,7 +16,7 @@ export class ICU4XLocale { * This will run the complete locale parsing algorithm. If code size and performance are critical and the locale is of a known shape (such as `aa-BB`) use `create_und`, `set_language`, `set_script`, and `set_region`. - * See the {@link https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_bytes Rust documentation for `try_from_bytes`} for more information. + * See the {@link https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_str Rust documentation for `try_from_str`} for more information. * @throws {@link FFIError}<{@link ICU4XLocaleParseError}> */ static create_from_string(name: string): ICU4XLocale | never; @@ -51,7 +51,7 @@ export class ICU4XLocale { * See the {@link https://docs.rs/icu/latest/icu/locale/struct.Locale.html#structfield.extensions Rust documentation for `extensions`} for more information. */ - get_unicode_extension(bytes: string): string | undefined; + get_unicode_extension(s: string): string | undefined; /** @@ -65,10 +65,10 @@ export class ICU4XLocale { * Set the language part of the {@link ICU4XLocale `ICU4XLocale`}. - * See the {@link https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_bytes Rust documentation for `try_from_bytes`} for more information. + * See the {@link https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_str Rust documentation for `try_from_str`} for more information. * @throws {@link FFIError}<{@link ICU4XLocaleParseError}> */ - set_language(bytes: string): void | never; + set_language(s: string): void | never; /** @@ -82,10 +82,10 @@ export class ICU4XLocale { * Set the region part of the {@link ICU4XLocale `ICU4XLocale`}. - * See the {@link https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_bytes Rust documentation for `try_from_bytes`} for more information. + * See the {@link https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_str Rust documentation for `try_from_str`} for more information. * @throws {@link FFIError}<{@link ICU4XLocaleParseError}> */ - set_region(bytes: string): void | never; + set_region(s: string): void | never; /** @@ -99,10 +99,10 @@ export class ICU4XLocale { * Set the script part of the {@link ICU4XLocale `ICU4XLocale`}. Pass an empty string to remove the script. - * See the {@link https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_bytes Rust documentation for `try_from_bytes`} for more information. + * See the {@link https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.try_from_str Rust documentation for `try_from_str`} for more information. * @throws {@link FFIError}<{@link ICU4XLocaleParseError}> */ - set_script(bytes: string): void | never; + set_script(s: string): void | never; /** @@ -113,7 +113,7 @@ export class ICU4XLocale { * See the {@link https://docs.rs/icu/latest/icu/locale/struct.Locale.html#method.canonicalize Rust documentation for `canonicalize`} for more information. * @throws {@link FFIError}<{@link ICU4XLocaleParseError}> */ - static canonicalize(bytes: string): string | never; + static canonicalize(s: string): string | never; /** diff --git a/ffi/capi/bindings/js/ICU4XLocale.mjs b/ffi/capi/bindings/js/ICU4XLocale.mjs index 2b82c6e441e..79f1922911d 100644 --- a/ffi/capi/bindings/js/ICU4XLocale.mjs +++ b/ffi/capi/bindings/js/ICU4XLocale.mjs @@ -51,15 +51,15 @@ export class ICU4XLocale { }); } - get_unicode_extension(arg_bytes) { - const buf_arg_bytes = diplomatRuntime.DiplomatBuf.str8(wasm, arg_bytes); + get_unicode_extension(arg_s) { + const buf_arg_s = diplomatRuntime.DiplomatBuf.str8(wasm, arg_s); const diplomat_out = diplomatRuntime.withDiplomatWrite(wasm, (write) => { return (() => { - const is_ok = wasm.ICU4XLocale_get_unicode_extension(this.underlying, buf_arg_bytes.ptr, buf_arg_bytes.size, write) == 1; + const is_ok = wasm.ICU4XLocale_get_unicode_extension(this.underlying, buf_arg_s.ptr, buf_arg_s.size, write) == 1; if (!is_ok) return; })(); }); - buf_arg_bytes.free(); + buf_arg_s.free(); return diplomat_out; } @@ -69,11 +69,11 @@ export class ICU4XLocale { }); } - set_language(arg_bytes) { - const buf_arg_bytes = diplomatRuntime.DiplomatBuf.str8(wasm, arg_bytes); + set_language(arg_s) { + const buf_arg_s = diplomatRuntime.DiplomatBuf.str8(wasm, arg_s); const diplomat_out = (() => { const diplomat_receive_buffer = wasm.diplomat_alloc(5, 4); - wasm.ICU4XLocale_set_language(diplomat_receive_buffer, this.underlying, buf_arg_bytes.ptr, buf_arg_bytes.size); + wasm.ICU4XLocale_set_language(diplomat_receive_buffer, this.underlying, buf_arg_s.ptr, buf_arg_s.size); const is_ok = diplomatRuntime.resultFlag(wasm, diplomat_receive_buffer, 4); if (is_ok) { const ok_value = {}; @@ -85,7 +85,7 @@ export class ICU4XLocale { throw new diplomatRuntime.FFIError(throw_value); } })(); - buf_arg_bytes.free(); + buf_arg_s.free(); return diplomat_out; } @@ -98,11 +98,11 @@ export class ICU4XLocale { }); } - set_region(arg_bytes) { - const buf_arg_bytes = diplomatRuntime.DiplomatBuf.str8(wasm, arg_bytes); + set_region(arg_s) { + const buf_arg_s = diplomatRuntime.DiplomatBuf.str8(wasm, arg_s); const diplomat_out = (() => { const diplomat_receive_buffer = wasm.diplomat_alloc(5, 4); - wasm.ICU4XLocale_set_region(diplomat_receive_buffer, this.underlying, buf_arg_bytes.ptr, buf_arg_bytes.size); + wasm.ICU4XLocale_set_region(diplomat_receive_buffer, this.underlying, buf_arg_s.ptr, buf_arg_s.size); const is_ok = diplomatRuntime.resultFlag(wasm, diplomat_receive_buffer, 4); if (is_ok) { const ok_value = {}; @@ -114,7 +114,7 @@ export class ICU4XLocale { throw new diplomatRuntime.FFIError(throw_value); } })(); - buf_arg_bytes.free(); + buf_arg_s.free(); return diplomat_out; } @@ -127,11 +127,11 @@ export class ICU4XLocale { }); } - set_script(arg_bytes) { - const buf_arg_bytes = diplomatRuntime.DiplomatBuf.str8(wasm, arg_bytes); + set_script(arg_s) { + const buf_arg_s = diplomatRuntime.DiplomatBuf.str8(wasm, arg_s); const diplomat_out = (() => { const diplomat_receive_buffer = wasm.diplomat_alloc(5, 4); - wasm.ICU4XLocale_set_script(diplomat_receive_buffer, this.underlying, buf_arg_bytes.ptr, buf_arg_bytes.size); + wasm.ICU4XLocale_set_script(diplomat_receive_buffer, this.underlying, buf_arg_s.ptr, buf_arg_s.size); const is_ok = diplomatRuntime.resultFlag(wasm, diplomat_receive_buffer, 4); if (is_ok) { const ok_value = {}; @@ -143,16 +143,16 @@ export class ICU4XLocale { throw new diplomatRuntime.FFIError(throw_value); } })(); - buf_arg_bytes.free(); + buf_arg_s.free(); return diplomat_out; } - static canonicalize(arg_bytes) { - const buf_arg_bytes = diplomatRuntime.DiplomatBuf.str8(wasm, arg_bytes); + static canonicalize(arg_s) { + const buf_arg_s = diplomatRuntime.DiplomatBuf.str8(wasm, arg_s); const diplomat_out = diplomatRuntime.withDiplomatWrite(wasm, (write) => { return (() => { const diplomat_receive_buffer = wasm.diplomat_alloc(5, 4); - wasm.ICU4XLocale_canonicalize(diplomat_receive_buffer, buf_arg_bytes.ptr, buf_arg_bytes.size, write); + wasm.ICU4XLocale_canonicalize(diplomat_receive_buffer, buf_arg_s.ptr, buf_arg_s.size, write); const is_ok = diplomatRuntime.resultFlag(wasm, diplomat_receive_buffer, 4); if (is_ok) { const ok_value = {}; @@ -165,7 +165,7 @@ export class ICU4XLocale { } })(); }); - buf_arg_bytes.free(); + buf_arg_s.free(); return diplomat_out; } diff --git a/ffi/capi/src/displaynames.rs b/ffi/capi/src/displaynames.rs index 847ba0dd775..fe2d7dcc1da 100644 --- a/ffi/capi/src/displaynames.rs +++ b/ffi/capi/src/displaynames.rs @@ -118,7 +118,7 @@ pub mod ffi { ) -> Result<(), ICU4XLocaleParseError> { let _infallible = self .0 - .of(Region::try_from_bytes(region)?) + .of(Region::try_from_utf8(region)?) .unwrap_or("") .write_to(write); Ok(()) diff --git a/ffi/capi/src/fallbacker.rs b/ffi/capi/src/fallbacker.rs index 8a294829d72..b70298f0d3d 100644 --- a/ffi/capi/src/fallbacker.rs +++ b/ffi/capi/src/fallbacker.rs @@ -184,9 +184,7 @@ impl TryFrom> for icu_locale::fallback::Local result.priority = other.priority.into(); result.extension_key = match other.extension_key { b"" => None, - s => Some(icu_locale_core::extensions::unicode::Key::try_from_bytes( - s, - )?), + s => Some(icu_locale_core::extensions::unicode::Key::try_from_utf8(s)?), }; result.fallback_supplement = match other.fallback_supplement { ffi::ICU4XLocaleFallbackSupplement::None => None, diff --git a/ffi/capi/src/locale_core.rs b/ffi/capi/src/locale_core.rs index befb39caedf..59e5db3ebf0 100644 --- a/ffi/capi/src/locale_core.rs +++ b/ffi/capi/src/locale_core.rs @@ -24,13 +24,14 @@ pub mod ffi { /// This will run the complete locale parsing algorithm. If code size and /// performance are critical and the locale is of a known shape (such as /// `aa-BB`) use `create_und`, `set_language`, `set_script`, and `set_region`. - #[diplomat::rust_link(icu::locale::Locale::try_from_bytes, FnInStruct)] + #[diplomat::rust_link(icu::locale::Locale::try_from_str, FnInStruct)] + #[diplomat::rust_link(icu::locale::Locale::try_from_utf8, FnInStruct, hidden)] #[diplomat::rust_link(icu::locale::Locale::from_str, FnInStruct, hidden)] #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "from_string")] pub fn create_from_string( name: &DiplomatStr, ) -> Result, ICU4XLocaleParseError> { - Ok(Box::new(ICU4XLocale(Locale::try_from_bytes(name)?))) + Ok(Box::new(ICU4XLocale(Locale::try_from_utf8(name)?))) } /// Construct a default undefined [`ICU4XLocale`] "und". @@ -58,10 +59,10 @@ pub mod ffi { #[diplomat::rust_link(icu::locale::Locale::extensions, StructField)] pub fn get_unicode_extension( &self, - bytes: &DiplomatStr, + s: &DiplomatStr, write: &mut diplomat_runtime::DiplomatWrite, ) -> Option<()> { - Key::try_from_bytes(bytes) + Key::try_from_utf8(s) .ok() .and_then(|k| self.0.extensions.unicode.keywords.get(&k)) .map(|v| { @@ -77,13 +78,14 @@ pub mod ffi { } /// Set the language part of the [`ICU4XLocale`]. - #[diplomat::rust_link(icu::locale::Locale::try_from_bytes, FnInStruct)] + #[diplomat::rust_link(icu::locale::Locale::try_from_str, FnInStruct)] + #[diplomat::rust_link(icu::locale::Locale::try_from_utf8, FnInStruct, hidden)] #[diplomat::attr(supports = accessors, setter = "language")] - pub fn set_language(&mut self, bytes: &DiplomatStr) -> Result<(), ICU4XLocaleParseError> { - self.0.id.language = if bytes.is_empty() { + pub fn set_language(&mut self, s: &DiplomatStr) -> Result<(), ICU4XLocaleParseError> { + self.0.id.language = if s.is_empty() { Language::UND } else { - Language::try_from_bytes(bytes)? + Language::try_from_utf8(s)? }; Ok(()) } @@ -98,13 +100,14 @@ pub mod ffi { } /// Set the region part of the [`ICU4XLocale`]. - #[diplomat::rust_link(icu::locale::Locale::try_from_bytes, FnInStruct)] + #[diplomat::rust_link(icu::locale::Locale::try_from_str, FnInStruct)] + #[diplomat::rust_link(icu::locale::Locale::try_from_utf8, FnInStruct, hidden)] #[diplomat::attr(all(supports = accessors, not(dart)), setter = "region")] - pub fn set_region(&mut self, bytes: &DiplomatStr) -> Result<(), ICU4XLocaleParseError> { - self.0.id.region = if bytes.is_empty() { + pub fn set_region(&mut self, s: &DiplomatStr) -> Result<(), ICU4XLocaleParseError> { + self.0.id.region = if s.is_empty() { None } else { - Some(Region::try_from_bytes(bytes)?) + Some(Region::try_from_utf8(s)?) }; Ok(()) } @@ -119,13 +122,14 @@ pub mod ffi { } /// Set the script part of the [`ICU4XLocale`]. Pass an empty string to remove the script. - #[diplomat::rust_link(icu::locale::Locale::try_from_bytes, FnInStruct)] + #[diplomat::rust_link(icu::locale::Locale::try_from_str, FnInStruct)] + #[diplomat::rust_link(icu::locale::Locale::try_from_utf8, FnInStruct, hidden)] #[diplomat::attr(all(supports = accessors, not(dart)), setter = "script")] - pub fn set_script(&mut self, bytes: &DiplomatStr) -> Result<(), ICU4XLocaleParseError> { - self.0.id.script = if bytes.is_empty() { + pub fn set_script(&mut self, s: &DiplomatStr) -> Result<(), ICU4XLocaleParseError> { + self.0.id.script = if s.is_empty() { None } else { - Some(Script::try_from_bytes(bytes)?) + Some(Script::try_from_utf8(s)?) }; Ok(()) } @@ -135,10 +139,10 @@ pub mod ffi { /// Use ICU4XLocaleCanonicalizer for better control and functionality #[diplomat::rust_link(icu::locale::Locale::canonicalize, FnInStruct)] pub fn canonicalize( - bytes: &DiplomatStr, + s: &DiplomatStr, write: &mut DiplomatWrite, ) -> Result<(), ICU4XLocaleParseError> { - let _infallible = Locale::canonicalize(bytes)?.write_to(write); + let _infallible = Locale::canonicalize(s)?.write_to(write); Ok(()) } /// Returns a string representation of [`ICU4XLocale`]. diff --git a/ffi/capi/src/timezone.rs b/ffi/capi/src/timezone.rs index 24a63e94a05..774017951ba 100644 --- a/ffi/capi/src/timezone.rs +++ b/ffi/capi/src/timezone.rs @@ -20,16 +20,18 @@ pub mod ffi { impl ICU4XCustomTimeZone { /// Creates a time zone from an offset string. - #[diplomat::rust_link(icu::timezone::CustomTimeZone::from_str, FnInStruct)] - #[diplomat::rust_link(icu::timezone::CustomTimeZone::try_from_bytes, FnInStruct, hidden)] + #[diplomat::rust_link(icu::timezone::CustomTimeZone::try_from_str, FnInStruct)] + #[diplomat::rust_link(icu::timezone::CustomTimeZone::try_from_utf8, FnInStruct, hidden)] + #[diplomat::rust_link(icu::timezone::CustomTimeZone::from_str, FnInStruct, hidden)] + #[diplomat::rust_link(icu::timezone::GmtOffset::try_from_str, FnInStruct, hidden)] + #[diplomat::rust_link(icu::timezone::GmtOffset::try_from_utf8, FnInStruct, hidden)] #[diplomat::rust_link(icu::timezone::GmtOffset::from_str, FnInStruct, hidden)] - #[diplomat::rust_link(icu::timezone::GmtOffset::try_from_bytes, FnInStruct, hidden)] #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "from_string")] pub fn create_from_string( s: &DiplomatStr, ) -> Result, ICU4XTimeZoneInvalidOffsetError> { Ok(Box::new(ICU4XCustomTimeZone::from( - CustomTimeZone::try_from_bytes(s)?, + CustomTimeZone::try_from_utf8(s)?, ))) } diff --git a/ffi/capi/src/units_converter.rs b/ffi/capi/src/units_converter.rs index 48110ec91c8..4a29f608aec 100644 --- a/ffi/capi/src/units_converter.rs +++ b/ffi/capi/src/units_converter.rs @@ -78,7 +78,7 @@ pub mod ffi { )] pub fn parse(&self, unit_id: &DiplomatStr) -> Option> { self.0 - .try_from_bytes(unit_id) + .try_from_utf8(unit_id) .ok() .map(ICU4XMeasureUnit) .map(Box::new) diff --git a/provider/bikeshed/src/decimal/mod.rs b/provider/bikeshed/src/decimal/mod.rs index 71c8f274161..042b089193c 100644 --- a/provider/bikeshed/src/decimal/mod.rs +++ b/provider/bikeshed/src/decimal/mod.rs @@ -93,7 +93,7 @@ impl DatagenProvider { let mut data_locale = DataLocale::from(&langid); data_locale.set_unicode_ext( key!("nu"), - Value::try_from_bytes(nsname.as_bytes()) + Value::try_from_str(&nsname) .expect("CLDR should have valid numbering system names"), ); (data_locale, Default::default()) diff --git a/provider/bikeshed/src/displaynames/region.rs b/provider/bikeshed/src/displaynames/region.rs index 53ca626c186..7da92e6c2c4 100644 --- a/provider/bikeshed/src/displaynames/region.rs +++ b/provider/bikeshed/src/displaynames/region.rs @@ -10,7 +10,6 @@ use icu::experimental::displaynames::provider::*; use icu::locale::subtags::Region; use icu_provider::prelude::*; use std::collections::{BTreeMap, HashSet}; -use std::str::FromStr; impl DataProvider for DatagenProvider { fn load( @@ -67,9 +66,9 @@ impl TryFrom<&cldr_serde::displaynames::region::Resource> for RegionDisplayNames let mut short_names = BTreeMap::new(); for (region, value) in other.main.value.localedisplaynames.regions.iter() { if let Some(region) = region.strip_suffix(SHORT_SUBSTRING) { - short_names.insert(Region::from_str(region)?.into_tinystr(), value.as_str()); + short_names.insert(Region::try_from_str(region)?.into_tinystr(), value.as_str()); } else if !region.contains(ALT_SUBSTRING) { - names.insert(Region::from_str(region)?.into_tinystr(), value.as_str()); + names.insert(Region::try_from_str(region)?.into_tinystr(), value.as_str()); } } Ok(Self { diff --git a/provider/bikeshed/src/displaynames/script.rs b/provider/bikeshed/src/displaynames/script.rs index a465e83db01..4748bd6c15e 100644 --- a/provider/bikeshed/src/displaynames/script.rs +++ b/provider/bikeshed/src/displaynames/script.rs @@ -10,7 +10,6 @@ use icu::experimental::displaynames::provider::*; use icu::locale::{subtags::Script, ParseError}; use icu_provider::prelude::*; use std::collections::{BTreeMap, HashSet}; -use std::str::FromStr; impl DataProvider for DatagenProvider { fn load( @@ -69,9 +68,15 @@ impl TryFrom<&cldr_serde::displaynames::script::Resource> for ScriptDisplayNames let mut short_names = BTreeMap::new(); for entry in other.main.value.localedisplaynames.scripts.iter() { if let Some(script) = entry.0.strip_suffix(ALT_SHORT_SUBSTRING) { - short_names.insert(Script::from_str(script)?.into_tinystr(), entry.1.as_str()); + short_names.insert( + Script::try_from_str(script)?.into_tinystr(), + entry.1.as_str(), + ); } else if !entry.0.contains(ALT_SUBSTRING) { - names.insert(Script::from_str(entry.0)?.into_tinystr(), entry.1.as_str()); + names.insert( + Script::try_from_str(entry.0)?.into_tinystr(), + entry.1.as_str(), + ); } } Ok(Self { diff --git a/provider/bikeshed/src/displaynames/variant.rs b/provider/bikeshed/src/displaynames/variant.rs index 22ac91bc1f4..086e9b6f170 100644 --- a/provider/bikeshed/src/displaynames/variant.rs +++ b/provider/bikeshed/src/displaynames/variant.rs @@ -10,7 +10,6 @@ use icu::experimental::displaynames::provider::*; use icu::locale::{subtags::Variant, ParseError}; use icu_provider::prelude::*; use std::collections::{BTreeMap, HashSet}; -use std::str::FromStr; impl DataProvider for DatagenProvider { fn load( @@ -66,7 +65,10 @@ impl TryFrom<&cldr_serde::displaynames::variant::Resource> for VariantDisplayNam for entry in other.main.value.localedisplaynames.variants.iter() { // TODO: Support alt variants for variant display names. if !entry.0.contains(ALT_SUBSTRING) { - names.insert(Variant::from_str(entry.0)?.into_tinystr(), entry.1.as_str()); + names.insert( + Variant::try_from_str(entry.0)?.into_tinystr(), + entry.1.as_str(), + ); } } Ok(Self { diff --git a/provider/bikeshed/src/units/helpers.rs b/provider/bikeshed/src/units/helpers.rs index d0a0683218f..1e8d55443dd 100644 --- a/provider/bikeshed/src/units/helpers.rs +++ b/provider/bikeshed/src/units/helpers.rs @@ -159,10 +159,9 @@ pub(crate) fn extract_conversion_info<'data>( Exactness::Approximate }; - let base_unit = match parser.try_from_bytes(base_unit.as_bytes()) { - Ok(base_unit) => base_unit, - Err(_) => return Err(DataError::custom("the base unit is not valid")), - }; + let base_unit = parser + .try_from_str(base_unit) + .map_err(|_| DataError::custom("the base unit is not valid"))?; Ok(ConversionInfo { basic_units: ZeroVec::from_iter(base_unit.contained_units), diff --git a/provider/blob/tests/test_versions.rs b/provider/blob/tests/test_versions.rs index c4e90616195..77967cc92ed 100644 --- a/provider/blob/tests/test_versions.rs +++ b/provider/blob/tests/test_versions.rs @@ -166,7 +166,7 @@ impl IterableDataProvider for ManyLocalesProvider { for i2 in LOWERCASE { bytes[2] = i2; let locale = - LanguageIdentifier::try_from_bytes(&bytes).expect("locale must parse"); + LanguageIdentifier::try_from_utf8(&bytes).expect("locale must parse"); r.insert((locale.into(), Default::default())); } } diff --git a/provider/datagen/src/driver.rs b/provider/datagen/src/driver.rs index 73e0e00b6cd..8d9469c0b77 100644 --- a/provider/datagen/src/driver.rs +++ b/provider/datagen/src/driver.rs @@ -277,15 +277,15 @@ impl FromStr for LocaleFamily { .ok_or(LocaleFamilyParseError::InvalidFamily)?; match first { b'^' => Ok(Self { - langid: Some(LanguageIdentifier::try_from_bytes(remainder)?), + langid: Some(LanguageIdentifier::try_from_utf8(remainder)?), annotations: LocaleFamilyAnnotations::without_descendants(), }), b'%' => Ok(Self { - langid: Some(LanguageIdentifier::try_from_bytes(remainder)?), + langid: Some(LanguageIdentifier::try_from_utf8(remainder)?), annotations: LocaleFamilyAnnotations::without_ancestors(), }), b'@' => Ok(Self { - langid: Some(LanguageIdentifier::try_from_bytes(remainder)?), + langid: Some(LanguageIdentifier::try_from_utf8(remainder)?), annotations: LocaleFamilyAnnotations::single(), }), b if b.is_ascii_alphanumeric() => Ok(Self { diff --git a/utils/pattern/src/common.rs b/utils/pattern/src/common.rs index 06a773b2e68..053ab9854d7 100644 --- a/utils/pattern/src/common.rs +++ b/utils/pattern/src/common.rs @@ -75,7 +75,7 @@ pub trait PatternBackend: crate::private::Sealed + 'static { /// The type of error that the [`TryWriteable`] for this backend can return. type Error<'a>; - /// The type of error that the [`PatternBackend::try_store_from_bytes`] can return. + /// The type of error that the [`PatternBackend::try_store_from_utf8`] can return. type StoreFromBytesError; /// The unsized type of the store required for this backend, usually `str` or `[u8]`. @@ -88,7 +88,7 @@ pub trait PatternBackend: crate::private::Sealed + 'static { /// Converts a byte slice store to this pattern backend's store. /// Does not perform validation of the store. #[doc(hidden)] // TODO(#4467): Should be internal - fn try_store_from_bytes(bytes: &[u8]) -> Result<&Self::Store, Self::StoreFromBytesError>; + fn try_store_from_utf8(bytes: &[u8]) -> Result<&Self::Store, Self::StoreFromBytesError>; /// Checks a store for validity, returning an error if invalid. #[doc(hidden)] // TODO(#4467): Should be internal diff --git a/utils/pattern/src/double.rs b/utils/pattern/src/double.rs index ceb38a21e82..f95033807eb 100644 --- a/utils/pattern/src/double.rs +++ b/utils/pattern/src/double.rs @@ -276,7 +276,7 @@ impl PatternBackend for DoublePlaceholder { type Iter<'a> = DoublePlaceholderPatternIterator<'a>; #[inline] - fn try_store_from_bytes(bytes: &[u8]) -> Result<&Self::Store, Self::StoreFromBytesError> { + fn try_store_from_utf8(bytes: &[u8]) -> Result<&Self::Store, Self::StoreFromBytesError> { core::str::from_utf8(bytes) } diff --git a/utils/pattern/src/error.rs b/utils/pattern/src/error.rs index 5bbe5eb853f..30654506c63 100644 --- a/utils/pattern/src/error.rs +++ b/utils/pattern/src/error.rs @@ -13,7 +13,7 @@ pub enum PatternError { InvalidPlaceholder, } -/// Error type for [`crate::Pattern::try_from_bytes_store`]. +/// Error type for [`crate::Pattern::try_from_utf8_store`]. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[non_exhaustive] pub enum PatternOrUtf8Error { diff --git a/utils/pattern/src/frontend/mod.rs b/utils/pattern/src/frontend/mod.rs index a67d4155387..e2d6bcf08f7 100644 --- a/utils/pattern/src/frontend/mod.rs +++ b/utils/pattern/src/frontend/mod.rs @@ -168,7 +168,7 @@ impl<'a, B> Pattern where B: PatternBackend, { - /// Creates a pattern from its store encoded as bytes. + /// Creates a pattern from its store encoded as UTF-8. /// /// # Examples /// @@ -176,13 +176,13 @@ where /// use icu_pattern::Pattern; /// use icu_pattern::SinglePlaceholder; /// - /// Pattern::::try_from_bytes_store(b"\x01 days") + /// Pattern::::try_from_utf8_store(b"\x01 days") /// .expect("single placeholder pattern"); /// ``` - pub fn try_from_bytes_store( - bytes: &'a [u8], + pub fn try_from_utf8_store( + code_units: &'a [u8], ) -> Result> { - let store = B::try_store_from_bytes(bytes).map_err(PatternOrUtf8Error::Utf8)?; + let store = B::try_store_from_utf8(code_units).map_err(PatternOrUtf8Error::Utf8)?; B::validate_store(store).map_err(PatternOrUtf8Error::Pattern)?; Ok(Self { _backend: PhantomData, diff --git a/utils/pattern/src/multi_named.rs b/utils/pattern/src/multi_named.rs index 39e616a2e4b..5679b54f8ad 100644 --- a/utils/pattern/src/multi_named.rs +++ b/utils/pattern/src/multi_named.rs @@ -320,7 +320,7 @@ impl PatternBackend for MultiNamedPlaceholder { type Iter<'a> = MultiNamedPlaceholderPatternIterator<'a>; #[inline] - fn try_store_from_bytes(bytes: &[u8]) -> Result<&Self::Store, Self::StoreFromBytesError> { + fn try_store_from_utf8(bytes: &[u8]) -> Result<&Self::Store, Self::StoreFromBytesError> { core::str::from_utf8(bytes) } diff --git a/utils/pattern/src/single.rs b/utils/pattern/src/single.rs index 612feca78a2..f7820d4f11d 100644 --- a/utils/pattern/src/single.rs +++ b/utils/pattern/src/single.rs @@ -177,7 +177,7 @@ impl PatternBackend for SinglePlaceholder { type Iter<'a> = SinglePlaceholderPatternIterator<'a>; #[inline] - fn try_store_from_bytes(utf8: &[u8]) -> Result<&Self::Store, Self::StoreFromBytesError> { + fn try_store_from_utf8(utf8: &[u8]) -> Result<&Self::Store, Self::StoreFromBytesError> { core::str::from_utf8(utf8) } diff --git a/utils/preferences/src/extensions/unicode/keywords/region_override.rs b/utils/preferences/src/extensions/unicode/keywords/region_override.rs index b11c3379b95..cd04f2197e0 100644 --- a/utils/preferences/src/extensions/unicode/keywords/region_override.rs +++ b/utils/preferences/src/extensions/unicode/keywords/region_override.rs @@ -20,9 +20,7 @@ struct_keyword!( .ok_or(PreferencesParseError::InvalidKeywordValue) }, |input: RegionOverride| { - Value::from_subtag(Some( - Subtag::try_from_bytes(input.0.to_string().as_bytes()).unwrap(), - )) + Value::from_subtag(Some(Subtag::try_from_str(&input.0.to_string()).unwrap())) } ); @@ -56,7 +54,7 @@ mod test { assert_eq!(rg.0.suffix, subdivision_suffix!("zzzz")); for i in &["4aabel", "a4bel", "ukabcde"] { - let val = unicode::Value::try_from_bytes(i.as_bytes()).unwrap(); + let val = unicode::Value::try_from_str(i).unwrap(); let rg: Result = val.try_into(); assert!(rg.is_err()); } diff --git a/utils/preferences/src/extensions/unicode/keywords/regional_subdivision.rs b/utils/preferences/src/extensions/unicode/keywords/regional_subdivision.rs index a3c313d442f..39795e9a884 100644 --- a/utils/preferences/src/extensions/unicode/keywords/regional_subdivision.rs +++ b/utils/preferences/src/extensions/unicode/keywords/regional_subdivision.rs @@ -22,9 +22,7 @@ struct_keyword!( .ok_or(PreferencesParseError::InvalidKeywordValue) }, |input: RegionalSubdivision| { - Value::from_subtag(Some( - Subtag::try_from_bytes(input.0.to_string().as_bytes()).unwrap(), - )) + Value::from_subtag(Some(Subtag::try_from_str(&input.0.to_string()).unwrap())) } ); @@ -51,7 +49,7 @@ mod test { assert_eq!(rg.suffix, subdivision_suffix!("sct")); for i in &["4aabel", "a4bel", "ukabcde"] { - let val = unicode::Value::try_from_bytes(i.as_bytes()).unwrap(); + let val = unicode::Value::try_from_str(i).unwrap(); let rg: Result = val.try_into(); assert!(rg.is_err()); } diff --git a/utils/tinystr/src/ascii.rs b/utils/tinystr/src/ascii.rs index bcd04b5120c..e245617580a 100644 --- a/utils/tinystr/src/ascii.rs +++ b/utils/tinystr/src/ascii.rs @@ -16,16 +16,23 @@ pub struct TinyAsciiStr { } impl TinyAsciiStr { + #[inline] + pub const fn try_from_str(s: &str) -> Result { + Self::try_from_utf8(s.as_bytes()) + } + /// Creates a `TinyAsciiStr` from the given UTF-8 slice. - /// `bytes` may contain at most `N` non-null ASCII code points. - pub const fn try_from_utf8(bytes: &[u8]) -> Result { - Self::try_from_utf8_inner(bytes, 0, bytes.len(), false) + /// `code_units` may contain at most `N` non-null ASCII code points. + #[inline] + pub const fn try_from_utf8(code_units: &[u8]) -> Result { + Self::try_from_utf8_inner(code_units, 0, code_units.len(), false) } /// Creates a `TinyAsciiStr` from the given UTF-16 slice. - /// `code_points` may contain at most `N` non-null ASCII code points. - pub const fn try_from_utf16(code_points: &[u16]) -> Result { - Self::try_from_utf16_inner(code_points, 0, code_points.len(), false) + /// `code_units` may contain at most `N` non-null ASCII code points. + #[inline] + pub const fn try_from_utf16(code_units: &[u16]) -> Result { + Self::try_from_utf16_inner(code_units, 0, code_units.len(), false) } /// Creates a `TinyAsciiStr` from a UTF-8 slice, replacing invalid code units. @@ -35,16 +42,20 @@ impl TinyAsciiStr { /// will be replaced with the replacement byte. /// /// The input slice will be truncated if its length exceeds `N`. - pub const fn from_utf8_lossy(bytes: &[u8], replacement: u8) -> Self { + pub const fn from_utf8_lossy(code_units: &[u8], replacement: u8) -> Self { let mut out = [0; N]; let mut i = 0; // Ord is not available in const, so no `.min(N)` - let len = if bytes.len() > N { N } else { bytes.len() }; + let len = if code_units.len() > N { + N + } else { + code_units.len() + }; // Indexing is protected by the len check above #[allow(clippy::indexing_slicing)] while i < len { - let b = bytes[i]; + let b = code_units[i]; if b > 0 && b < 0x80 { out[i] = b; } else { @@ -66,20 +77,20 @@ impl TinyAsciiStr { /// will be replaced with the replacement byte. /// /// The input slice will be truncated if its length exceeds `N`. - pub const fn from_utf16_lossy(code_points: &[u16], replacement: u8) -> Self { + pub const fn from_utf16_lossy(code_units: &[u16], replacement: u8) -> Self { let mut out = [0; N]; let mut i = 0; // Ord is not available in const, so no `.min(N)` - let len = if code_points.len() > N { + let len = if code_units.len() > N { N } else { - code_points.len() + code_units.len() }; // Indexing is protected by the len check above #[allow(clippy::indexing_slicing)] while i < len { - let b = code_points[i]; + let b = code_units[i]; if b > 0 && b < 0x80 { out[i] = b as u8; } else { @@ -120,27 +131,28 @@ impl TinyAsciiStr { /// Equivalent to [`try_from_utf8(bytes[start..end])`](Self::try_from_utf8), /// but callable in a `const` context (which range indexing is not). + #[inline] pub const fn try_from_utf8_manual_slice( - bytes: &[u8], + code_units: &[u8], start: usize, end: usize, ) -> Result { - Self::try_from_utf8_inner(bytes, start, end, false) + Self::try_from_utf8_inner(code_units, start, end, false) } /// Equivalent to [`try_from_utf16(bytes[start..end])`](Self::try_from_utf16), /// but callable in a `const` context (which range indexing is not). + #[inline] pub const fn try_from_utf16_manual_slice( - code_points: &[u16], + code_units: &[u16], start: usize, end: usize, ) -> Result { - Self::try_from_utf16_inner(code_points, start, end, false) + Self::try_from_utf16_inner(code_units, start, end, false) } - #[inline] pub(crate) const fn try_from_utf8_inner( - bytes: &[u8], + code_units: &[u8], start: usize, end: usize, allow_trailing_null: bool, @@ -156,7 +168,7 @@ impl TinyAsciiStr { // Indexing is protected by TinyStrError::TooLarge #[allow(clippy::indexing_slicing)] while i < len { - let b = bytes[start + i]; + let b = code_units[start + i]; if b == 0 { found_null = true; @@ -182,7 +194,6 @@ impl TinyAsciiStr { }) } - #[inline] pub(crate) const fn try_from_utf16_inner( code_points: &[u16], start: usize, @@ -226,11 +237,6 @@ impl TinyAsciiStr { }) } - #[inline] - pub const fn try_from_str(s: &str) -> Result { - Self::try_from_utf8_inner(s.as_bytes(), 0, s.len(), false) - } - #[inline] pub const fn as_str(&self) -> &str { // as_utf8 is valid utf8 @@ -301,9 +307,9 @@ impl TinyAsciiStr { /// Must be called with a bytes array made of valid ASCII bytes, with no null bytes /// between ASCII characters #[must_use] - pub const unsafe fn from_utf8_unchecked(bytes: [u8; N]) -> Self { + pub const unsafe fn from_utf8_unchecked(code_units: [u8; N]) -> Self { Self { - bytes: AsciiByte::to_ascii_byte_array(&bytes), + bytes: AsciiByte::to_ascii_byte_array(&code_units), } } } @@ -923,7 +929,7 @@ mod test { fn check() { check_operation( |s| { - s == TinyAsciiStr::<16>::from_str(s) + s == TinyAsciiStr::<16>::try_from_str(s) .unwrap() .to_ascii_lowercase() .as_str() @@ -944,7 +950,7 @@ mod test { fn check() { check_operation( |s| { - s == TinyAsciiStr::<16>::from_str(s) + s == TinyAsciiStr::<16>::try_from_str(s) .unwrap() .to_ascii_titlecase() .as_str() @@ -965,7 +971,7 @@ mod test { fn check() { check_operation( |s| { - s == TinyAsciiStr::<16>::from_str(s) + s == TinyAsciiStr::<16>::try_from_str(s) .unwrap() .to_ascii_uppercase() .as_str() @@ -989,7 +995,7 @@ mod test { // Check alphabetic s.chars().all(|c| c.is_ascii_alphabetic()) && // Check lowercase - s == TinyAsciiStr::<16>::from_str(s) + s == TinyAsciiStr::<16>::try_from_str(s) .unwrap() .to_ascii_lowercase() .as_str() @@ -1013,7 +1019,7 @@ mod test { // Check alphabetic s.chars().all(|c| c.is_ascii_alphabetic()) && // Check titlecase - s == TinyAsciiStr::<16>::from_str(s) + s == TinyAsciiStr::<16>::try_from_str(s) .unwrap() .to_ascii_titlecase() .as_str() @@ -1037,7 +1043,7 @@ mod test { // Check alphabetic s.chars().all(|c| c.is_ascii_alphabetic()) && // Check uppercase - s == TinyAsciiStr::<16>::from_str(s) + s == TinyAsciiStr::<16>::try_from_str(s) .unwrap() .to_ascii_uppercase() .as_str()