Skip to main content

icu_capi/
locale_core.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5#[diplomat::bridge]
6#[diplomat::abi_rename = "icu4x_{0}_mv1"]
7pub mod ffi {
8    use alloc::boxed::Box;
9
10    use crate::unstable::errors::ffi::LocaleParseError;
11
12    use writeable::Writeable;
13
14    #[diplomat::opaque]
15    /// An ICU4X Locale, capable of representing strings like `"en-US"`.
16    #[diplomat::rust_link(icu::locale::Locale, Struct)]
17    #[diplomat::rust_link(icu::locale::DataLocale, Struct, hidden)]
18    #[diplomat::rust_link(icu::locale::DataLocale::into_locale, FnInStruct, hidden)]
19    pub struct Locale(pub icu_locale_core::Locale);
20
21    impl Locale {
22        /// Construct an [`Locale`] from an locale identifier.
23        ///
24        /// This will run the complete locale parsing algorithm. If code size and
25        /// performance are critical and the locale is of a known shape (such as
26        /// `aa-BB`) use `create_und`, `set_language`, `set_script`, and `set_region`.
27        #[diplomat::rust_link(icu::locale::Locale::try_from_str, FnInStruct)]
28        #[diplomat::rust_link(icu::locale::Locale::try_from_utf8, FnInStruct, hidden)]
29        #[diplomat::rust_link(icu::locale::Locale::from_str, FnInStruct, hidden)]
30        #[diplomat::rust_link(icu::locale::DataLocale::from_str, FnInStruct, hidden)]
31        #[diplomat::rust_link(icu::locale::DataLocale::try_from_str, FnInStruct, hidden)]
32        #[diplomat::rust_link(icu::locale::DataLocale::try_from_utf8, FnInStruct, hidden)]
33        #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)]
34        #[diplomat::demo(default_constructor)]
35        pub fn from_string(name: &DiplomatStr) -> Result<Box<Locale>, LocaleParseError> {
36            Ok(Box::new(Locale(icu_locale_core::Locale::try_from_utf8(
37                name,
38            )?)))
39        }
40
41        /// Construct a unknown [`Locale`] "und".
42        #[diplomat::rust_link(icu::locale::Locale::UNKNOWN, AssociatedConstantInStruct)]
43        #[diplomat::rust_link(icu::locale::DataLocale::default, FnInStruct, hidden)]
44        #[diplomat::rust_link(icu::locale::DataLocale::is_unknown, FnInStruct, hidden)]
45        #[diplomat::attr(all(supports = fallible_constructors, supports = named_constructors), named_constructor)]
46        pub fn unknown() -> Box<Locale> {
47            Box::new(Locale(icu_locale_core::Locale::UNKNOWN))
48        }
49
50        /// Clones the [`Locale`].
51        #[diplomat::rust_link(icu::locale::Locale, Struct)]
52        pub fn clone(&self) -> Box<Locale> {
53            Box::new(Locale(self.0.clone()))
54        }
55
56        /// Returns a string representation of the `LanguageIdentifier` part of
57        /// [`Locale`].
58        #[diplomat::rust_link(icu::locale::Locale::id, StructField)]
59        #[diplomat::attr(auto, getter)]
60        pub fn basename(&self, write: &mut diplomat_runtime::DiplomatWrite) {
61            let _infallible = self.0.id.write_to(write);
62        }
63
64        /// Returns a string representation of the unicode extension.
65        #[diplomat::rust_link(icu::locale::Locale::extensions, StructField)]
66        pub fn get_unicode_extension(
67            &self,
68            s: &DiplomatStr,
69            write: &mut diplomat_runtime::DiplomatWrite,
70        ) -> Option<()> {
71            icu_locale_core::extensions::unicode::Key::try_from_utf8(s)
72                .ok()
73                .and_then(|k| self.0.extensions.unicode.keywords.get(&k))
74                .map(|v| {
75                    let _infallible = v.write_to(write);
76                })
77        }
78
79        /// Set a Unicode extension.
80        #[diplomat::rust_link(icu::locale::Locale::extensions, StructField)]
81        pub fn set_unicode_extension(&mut self, k: &DiplomatStr, v: &DiplomatStr) -> Option<()> {
82            let k = icu_locale_core::extensions::unicode::Key::try_from_utf8(k).ok()?;
83            let v = icu_locale_core::extensions::unicode::Value::try_from_utf8(v).ok()?;
84            self.0.extensions.unicode.keywords.set(k, v);
85            Some(())
86        }
87
88        /// Returns a string representation of [`Locale`] language.
89        #[diplomat::rust_link(icu::locale::Locale::id, StructField)]
90        #[diplomat::attr(auto, getter)]
91        pub fn language(&self, write: &mut diplomat_runtime::DiplomatWrite) {
92            let _infallible = self.0.id.language.write_to(write);
93        }
94
95        /// Set the language part of the [`Locale`].
96        #[diplomat::rust_link(icu::locale::Locale::try_from_str, FnInStruct)]
97        #[diplomat::rust_link(icu::locale::Locale::try_from_utf8, FnInStruct, hidden)]
98        #[diplomat::attr(auto, setter = "language")]
99        pub fn set_language(&mut self, s: &DiplomatStr) -> Result<(), LocaleParseError> {
100            self.0.id.language = if s.is_empty() {
101                icu_locale_core::subtags::Language::UNKNOWN
102            } else {
103                icu_locale_core::subtags::Language::try_from_utf8(s)?
104            };
105            Ok(())
106        }
107
108        /// Returns a string representation of [`Locale`] region.
109        #[diplomat::rust_link(icu::locale::Locale::id, StructField)]
110        #[diplomat::attr(auto, getter)]
111        pub fn region(&self, write: &mut diplomat_runtime::DiplomatWrite) -> Option<()> {
112            self.0.id.region.map(|region| {
113                let _infallible = region.write_to(write);
114            })
115        }
116
117        /// Set the region part of the [`Locale`].
118        #[diplomat::rust_link(icu::locale::Locale::try_from_str, FnInStruct)]
119        #[diplomat::rust_link(icu::locale::Locale::try_from_utf8, FnInStruct, hidden)]
120        #[diplomat::attr(all(supports = accessors, not(dart)), setter = "region")]
121        pub fn set_region(&mut self, s: &DiplomatStr) -> Result<(), LocaleParseError> {
122            self.0.id.region = if s.is_empty() {
123                None
124            } else {
125                Some(icu_locale_core::subtags::Region::try_from_utf8(s)?)
126            };
127            Ok(())
128        }
129
130        /// Returns a string representation of [`Locale`] script.
131        #[diplomat::rust_link(icu::locale::Locale::id, StructField)]
132        #[diplomat::attr(auto, getter)]
133        pub fn script(&self, write: &mut diplomat_runtime::DiplomatWrite) -> Option<()> {
134            self.0.id.script.map(|script| {
135                let _infallible = script.write_to(write);
136            })
137        }
138
139        /// Set the script part of the [`Locale`]. Pass an empty string to remove the script.
140        #[diplomat::rust_link(icu::locale::Locale::try_from_str, FnInStruct)]
141        #[diplomat::rust_link(icu::locale::Locale::try_from_utf8, FnInStruct, hidden)]
142        #[diplomat::attr(all(supports = accessors, not(dart)), setter = "script")]
143        pub fn set_script(&mut self, s: &DiplomatStr) -> Result<(), LocaleParseError> {
144            self.0.id.script = if s.is_empty() {
145                None
146            } else {
147                Some(icu_locale_core::subtags::Script::try_from_utf8(s)?)
148            };
149            Ok(())
150        }
151
152        /// Normalizes a locale string.
153        #[diplomat::rust_link(icu::locale::Locale::normalize, FnInStruct)]
154        #[diplomat::rust_link(icu::locale::Locale::normalize_utf8, FnInStruct, hidden)]
155        pub fn normalize(
156            s: &DiplomatStr,
157            write: &mut DiplomatWrite,
158        ) -> Result<(), LocaleParseError> {
159            let _infallible = icu_locale_core::Locale::normalize_utf8(s)?.write_to(write);
160            Ok(())
161        }
162        /// Returns a string representation of [`Locale`].
163        #[diplomat::rust_link(icu::locale::Locale::write_to, FnInStruct)]
164        #[diplomat::rust_link(icu::locale::Locale::to_string, FnInStruct, hidden)]
165        #[diplomat::rust_link(icu::locale::DataLocale::to_string, FnInStruct, hidden)]
166        #[diplomat::rust_link(icu::locale::DataLocale::write_to, FnInStruct, hidden)]
167        #[diplomat::attr(auto, stringifier)]
168        pub fn to_string(&self, write: &mut diplomat_runtime::DiplomatWrite) {
169            let _infallible = self.0.write_to(write);
170        }
171
172        #[diplomat::rust_link(icu::locale::Locale::normalizing_eq, FnInStruct)]
173        pub fn normalizing_eq(&self, other: &DiplomatStr) -> bool {
174            if let Ok(other) = core::str::from_utf8(other) {
175                self.0.normalizing_eq(other)
176            } else {
177                // invalid UTF8 won't be allowed in locales anyway
178                false
179            }
180        }
181
182        #[diplomat::rust_link(icu::locale::Locale::strict_cmp, FnInStruct)]
183        pub fn compare_to_string(&self, other: &DiplomatStr) -> core::cmp::Ordering {
184            self.0.strict_cmp(other)
185        }
186
187        #[diplomat::rust_link(icu::locale::Locale::total_cmp, FnInStruct)]
188        #[diplomat::rust_link(icu::locale::DataLocale::strict_cmp, FnInStruct, hidden)]
189        #[diplomat::rust_link(icu::locale::DataLocale::total_cmp, FnInStruct, hidden)]
190        #[diplomat::attr(auto, comparison)]
191        pub fn compare_to(&self, other: &Self) -> core::cmp::Ordering {
192            self.0.total_cmp(&other.0)
193        }
194    }
195}
196
197impl ffi::Locale {
198    pub fn to_datalocale(&self) -> icu_provider::DataLocale {
199        (&self.0).into()
200    }
201}