diff --git a/components/locid/src/extensions/other/mod.rs b/components/locid/src/extensions/other/mod.rs index 8a7f36d4949..f629d76ae83 100644 --- a/components/locid/src/extensions/other/mod.rs +++ b/components/locid/src/extensions/other/mod.rs @@ -19,14 +19,11 @@ //! let mut loc: Locale = "en-US-a-foo-faa".parse().expect("Parsing failed."); //! ``` -mod subtag; - use crate::parser::ParserError; use crate::parser::SubtagIterator; use crate::shortvec::ShortBoxSlice; +use crate::subtags::Subtag; use alloc::vec::Vec; -#[doc(inline)] -pub use subtag::{subtag, Subtag}; /// A list of [`Other Use Extensions`] as defined in [`Unicode Locale /// Identifier`] specification. @@ -37,7 +34,8 @@ pub use subtag::{subtag, Subtag}; /// # Examples /// /// ``` -/// use icu::locid::extensions::other::{Other, Subtag}; +/// use icu::locid::extensions::other::Other; +/// use icu::locid::subtags::Subtag; /// /// let subtag1: Subtag = "foo".parse().expect("Failed to parse a Subtag."); /// let subtag2: Subtag = "bar".parse().expect("Failed to parse a Subtag."); @@ -64,7 +62,8 @@ impl Other { /// # Examples /// /// ``` - /// use icu::locid::extensions::other::{Other, Subtag}; + /// use icu::locid::extensions::other::Other; + /// use icu::locid::subtags::Subtag; /// /// let subtag1: Subtag = "foo".parse().expect("Failed to parse a Subtag."); /// let subtag2: Subtag = "bar".parse().expect("Failed to parse a Subtag."); diff --git a/components/locid/src/extensions/other/subtag.rs b/components/locid/src/extensions/other/subtag.rs deleted file mode 100644 index 03be569406f..00000000000 --- a/components/locid/src/extensions/other/subtag.rs +++ /dev/null @@ -1,36 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -impl_tinystr_subtag!( - /// A single item used in a list of [`Other`](super::Other) extensions. - /// - /// The subtag has to be an ASCII alphanumerical string no shorter than - /// two characters and no longer than eight. - /// - /// # Examples - /// - /// ``` - /// use icu::locid::extensions::other::subtag; - /// - /// assert_eq!(subtag!("Foo").as_str(), "foo"); - /// ``` - Subtag, - extensions::other, - subtag, - extensions_other_subtag, - 2..=8, - s, - s.is_ascii_alphanumeric(), - s.to_ascii_lowercase(), - s.is_ascii_alphanumeric() && s.is_ascii_lowercase(), - InvalidExtension, - ["foo12"], - ["y", "toolooong"], -); - -impl Subtag { - pub(crate) const fn valid_key(v: &[u8]) -> bool { - 2 <= v.len() && v.len() <= 8 - } -} diff --git a/components/locid/src/extensions/private/other.rs b/components/locid/src/extensions/private/other.rs index 810ffa2f499..8332a3a1772 100644 --- a/components/locid/src/extensions/private/other.rs +++ b/components/locid/src/extensions/private/other.rs @@ -13,10 +13,25 @@ impl_tinystr_subtag!( /// ``` /// use icu::locid::extensions::private::Subtag; /// - /// let subtag1: Subtag = "Foo".parse().expect("Failed to parse a Subtag."); + /// let subtag1: Subtag = "Foo".parse() + /// .expect("Failed to parse a Subtag."); /// /// assert_eq!(subtag1.as_str(), "foo"); /// ``` + /// + /// Notice: This is different from the generic [`Subtag`](crate::subtags::Subtag) + /// which is between two and eight characters. + /// + /// ``` + /// use icu::locid::extensions::private; + /// use icu::locid::subtags; + /// + /// let subtag: Result = "f".parse(); + /// assert!(subtag.is_ok()); + /// + /// let subtag: Result = "f".parse(); + /// assert!(subtag.is_err()); + /// ``` Subtag, extensions::private, subtag, diff --git a/components/locid/src/subtags/mod.rs b/components/locid/src/subtags/mod.rs index 9cc04dac8c1..6e5ca3cb6c0 100644 --- a/components/locid/src/subtags/mod.rs +++ b/components/locid/src/subtags/mod.rs @@ -60,3 +60,68 @@ pub use script::{script, Script}; #[doc(inline)] pub use variant::{variant, Variant}; pub use variants::Variants; + +impl_tinystr_subtag!( + /// A generic subtag. + /// + /// The subtag has to be an ASCII alphanumerical string no shorter than + /// two characters and no longer than eight. + /// + /// # Examples + /// + /// ``` + /// use icu::locid::subtags::Subtag; + /// + /// let subtag1: Subtag = "Foo".parse() + /// .expect("Failed to parse a Subtag."); + /// + /// assert_eq!(subtag1.as_str(), "foo"); + /// ``` + Subtag, + subtags, + subtag, + subtags_subtag, + 2..=8, + s, + s.is_ascii_alphanumeric(), + s.to_ascii_lowercase(), + s.is_ascii_alphanumeric() && s.is_ascii_lowercase(), + InvalidSubtag, + ["foo12"], + ["f", "toolooong"], +); + +impl Subtag { + pub(crate) const fn valid_key(v: &[u8]) -> bool { + 2 <= v.len() && v.len() <= 8 + } +} + +impl TryFrom> for Subtag { + type Error = crate::parser::errors::ParserError; + + fn try_from(value: tinystr::TinyAsciiStr) -> Result { + Self::try_from_bytes(value.as_bytes()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tinystr::tinystr; + + #[test] + fn test_subtag() { + let subtag = subtag!("foo"); + assert_eq!(subtag.as_str(), "foo"); + } + + #[test] + fn test_subtag_from_tinystr() { + let subtag = Subtag::try_from(tinystr!(3, "foo")); + assert!(subtag.is_ok()); + + let subtag = Subtag::try_from(tinystr!(1, "f")); + assert!(subtag.is_err()); + } +}