icu_locale_core/extensions/unicode/
mod.rs1mod attribute;
31mod attributes;
32mod key;
33mod keywords;
34mod subdivision;
35mod value;
36
37use core::cmp::Ordering;
38#[cfg(feature = "alloc")]
39use core::str::FromStr;
40
41#[doc(inline)]
42pub use attribute::{Attribute, attribute};
43pub use attributes::Attributes;
44#[doc(inline)]
45pub use key::{Key, key};
46pub use keywords::Keywords;
47#[doc(inline)]
48pub use subdivision::{SubdivisionId, SubdivisionSuffix, subdivision_suffix};
49#[doc(inline)]
50pub use value::{Value, value};
51
52#[cfg(feature = "alloc")]
53use super::ExtensionType;
54#[cfg(feature = "alloc")]
55use crate::parser::ParseError;
56#[cfg(feature = "alloc")]
57use crate::parser::SubtagIterator;
58
59pub(crate) const UNICODE_EXT_CHAR: char = 'u';
60pub(crate) const UNICODE_EXT_STR: &str = "u";
61
62#[derive(#[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::clone::Clone for Unicode {
#[inline]
fn clone(&self) -> Unicode {
Unicode {
keywords: ::core::clone::Clone::clone(&self.keywords),
attributes: ::core::clone::Clone::clone(&self.attributes),
}
}
}Clone, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::PartialEq for Unicode {
#[inline]
fn eq(&self, other: &Unicode) -> bool {
self.keywords == other.keywords && self.attributes == other.attributes
}
}PartialEq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::cmp::Eq for Unicode {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Keywords>;
let _: ::core::cmp::AssertParamIsEq<Attributes>;
}
}Eq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::fmt::Debug for Unicode {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "Unicode",
"keywords", &self.keywords, "attributes", &&self.attributes)
}
}Debug, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::default::Default for Unicode {
#[inline]
fn default() -> Unicode {
Unicode {
keywords: ::core::default::Default::default(),
attributes: ::core::default::Default::default(),
}
}
}Default, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl ::core::hash::Hash for Unicode {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.keywords, state);
::core::hash::Hash::hash(&self.attributes, state)
}
}Hash)]
90#[allow(clippy::exhaustive_structs)] pub struct Unicode {
92 pub keywords: Keywords,
95 pub attributes: Attributes,
97}
98
99impl Unicode {
100 #[inline]
110 pub const fn new() -> Self {
111 Self {
112 keywords: Keywords::new(),
113 attributes: Attributes::new(),
114 }
115 }
116
117 #[inline]
122 #[cfg(feature = "alloc")]
123 pub fn try_from_str(s: &str) -> Result<Self, ParseError> {
124 Self::try_from_utf8(s.as_bytes())
125 }
126
127 #[cfg(feature = "alloc")]
131 pub fn try_from_utf8(code_units: &[u8]) -> Result<Self, ParseError> {
132 let mut iter = SubtagIterator::new(code_units);
133
134 let ext = iter.next().ok_or(ParseError::InvalidExtension)?;
135 if let ExtensionType::Unicode = ExtensionType::try_from_byte_slice(ext)? {
136 return Self::try_from_iter(&mut iter);
137 }
138
139 Err(ParseError::InvalidExtension)
140 }
141
142 pub fn is_empty(&self) -> bool {
154 self.keywords.is_empty() && self.attributes.is_empty()
155 }
156
157 pub fn clear(&mut self) {
171 self.keywords.clear();
172 self.attributes.clear();
173 }
174
175 pub(crate) fn as_tuple(&self) -> (&Attributes, &Keywords) {
176 (&self.attributes, &self.keywords)
177 }
178
179 pub fn total_cmp(&self, other: &Self) -> Ordering {
186 self.as_tuple().cmp(&other.as_tuple())
187 }
188
189 #[cfg(feature = "alloc")]
190 pub(crate) fn try_from_iter(iter: &mut SubtagIterator) -> Result<Self, ParseError> {
191 let attributes = Attributes::from_iter(iter);
192 let keywords = Keywords::try_from_iter(iter)?;
193
194 if attributes.is_empty() && keywords.is_empty() {
196 return Err(ParseError::InvalidExtension);
197 }
198
199 Ok(Self {
200 keywords,
201 attributes,
202 })
203 }
204
205 pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F, with_ext: bool) -> Result<(), E>
206 where
207 F: FnMut(&str) -> Result<(), E>,
208 {
209 if !self.is_empty() {
210 if with_ext {
211 f(UNICODE_EXT_STR)?;
212 }
213 self.attributes.for_each_subtag_str(f)?;
214 self.keywords.for_each_subtag_str(f)?;
215 }
216 Ok(())
217 }
218
219 #[cfg(feature = "alloc")]
234 pub fn extend(&mut self, other: Unicode) {
235 self.keywords.extend_from_keywords(other.keywords);
236 self.attributes.extend_from_attributes(other.attributes);
237 }
238}
239
240#[cfg(feature = "alloc")]
242impl FromStr for Unicode {
243 type Err = ParseError;
244
245 #[inline]
246 fn from_str(s: &str) -> Result<Self, Self::Err> {
247 Self::try_from_str(s)
248 }
249}
250
251impl core::fmt::Display for Unicode {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
::writeable::Writeable::write_to(&self, f)
}
}writeable::impl_display_with_writeable!(Unicode, #[cfg(feature = "alloc")]);
252
253impl writeable::Writeable for Unicode {
254 fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
255 sink.write_char(UNICODE_EXT_CHAR)?;
256
257 if !self.attributes.is_empty() {
258 sink.write_char('-')?;
259 writeable::Writeable::write_to(&self.attributes, sink)?;
260 }
261 if !self.keywords.is_empty() {
262 sink.write_char('-')?;
263 writeable::Writeable::write_to(&self.keywords, sink)?;
264 }
265 Ok(())
266 }
267
268 fn writeable_length_hint(&self) -> writeable::LengthHint {
269 if self.is_empty() {
270 return writeable::LengthHint::exact(0);
271 }
272 let mut result = writeable::LengthHint::exact(1);
273 if !self.attributes.is_empty() {
274 result += writeable::Writeable::writeable_length_hint(&self.attributes) + 1;
275 }
276 if !self.keywords.is_empty() {
277 result += writeable::Writeable::writeable_length_hint(&self.keywords) + 1;
278 }
279 result
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use super::*;
286
287 #[test]
288 fn test_unicode_extension_fromstr() {
289 let ue: Unicode = "u-foo-hc-h12".parse().expect("Failed to parse Unicode");
290 assert_eq!(ue.to_string(), "u-foo-hc-h12");
291
292 let ue: Result<Unicode, _> = "u".parse();
293 assert!(ue.is_err());
294 }
295}