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