icu_locale_core/extensions/other/
mod.rs1#[cfg(feature = "alloc")]
23use core::str::FromStr;
24
25#[cfg(feature = "alloc")]
26use super::ExtensionType;
27#[cfg(feature = "alloc")]
28use crate::parser::ParseError;
29#[cfg(feature = "alloc")]
30use crate::parser::SubtagIterator;
31use crate::shortvec::ShortBoxSlice;
32use crate::subtags::Subtag;
33#[cfg(feature = "alloc")]
34use alloc::vec::Vec;
35
36#[derive(#[automatically_derived]
impl ::core::clone::Clone for Other {
#[inline]
fn clone(&self) -> Other {
Other {
ext: ::core::clone::Clone::clone(&self.ext),
keys: ::core::clone::Clone::clone(&self.keys),
}
}
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for Other {
#[inline]
fn eq(&self, other: &Other) -> bool {
self.ext == other.ext && self.keys == other.keys
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Other {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<u8>;
let _: ::core::cmp::AssertParamIsEq<ShortBoxSlice<Subtag>>;
}
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for Other {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "Other", "ext",
&self.ext, "keys", &&self.keys)
}
}Debug, #[automatically_derived]
impl ::core::default::Default for Other {
#[inline]
fn default() -> Other {
Other {
ext: ::core::default::Default::default(),
keys: ::core::default::Default::default(),
}
}
}Default, #[automatically_derived]
impl ::core::hash::Hash for Other {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.ext, state);
::core::hash::Hash::hash(&self.keys, state)
}
}Hash, #[automatically_derived]
impl ::core::cmp::PartialOrd for Other {
#[inline]
fn partial_cmp(&self, other: &Other)
-> ::core::option::Option<::core::cmp::Ordering> {
match ::core::cmp::PartialOrd::partial_cmp(&self.ext, &other.ext) {
::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
::core::cmp::PartialOrd::partial_cmp(&self.keys, &other.keys),
cmp => cmp,
}
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for Other {
#[inline]
fn cmp(&self, other: &Other) -> ::core::cmp::Ordering {
match ::core::cmp::Ord::cmp(&self.ext, &other.ext) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(&self.keys, &other.keys),
cmp => cmp,
}
}
}Ord)]
58pub struct Other {
59 ext: u8,
61 keys: ShortBoxSlice<Subtag>,
62}
63
64impl Other {
65 #[inline]
70 #[cfg(feature = "alloc")]
71 pub fn try_from_str(s: &str) -> Result<Self, ParseError> {
72 Self::try_from_utf8(s.as_bytes())
73 }
74
75 #[cfg(feature = "alloc")]
79 pub fn try_from_utf8(code_units: &[u8]) -> Result<Self, ParseError> {
80 let mut iter = SubtagIterator::new(code_units);
81
82 let ext = iter.next().ok_or(ParseError::InvalidExtension)?;
83 if let ExtensionType::Other(b) = ExtensionType::try_from_byte_slice(ext)? {
84 return Self::try_from_iter(b, &mut iter);
85 }
86
87 Err(ParseError::InvalidExtension)
88 }
89
90 #[cfg(feature = "alloc")]
111 pub fn from_vec_unchecked(ext: u8, keys: Vec<Subtag>) -> Self {
112 Self::from_short_slice_unchecked(ext, keys.into())
113 }
114
115 #[allow(dead_code)]
116 pub(crate) fn from_short_slice_unchecked(ext: u8, keys: ShortBoxSlice<Subtag>) -> Self {
117 if !ext.is_ascii_alphabetic() {
::core::panicking::panic("assertion failed: ext.is_ascii_alphabetic()")
};assert!(ext.is_ascii_alphabetic());
118 Self { ext, keys }
120 }
121
122 #[cfg(feature = "alloc")]
123 pub(crate) fn try_from_iter(ext: u8, iter: &mut SubtagIterator) -> Result<Self, ParseError> {
124 debug_assert!(matches!(
125 ExtensionType::try_from_byte(ext),
126 Ok(ExtensionType::Other(_)),
127 ));
128
129 let mut keys = ShortBoxSlice::new();
130 while let Some(subtag) = iter.peek() {
131 if !Subtag::valid_key(subtag) {
132 break;
133 }
134 if let Ok(key) = Subtag::try_from_utf8(subtag) {
135 keys.push(key);
136 }
137 iter.next();
138 }
139
140 if keys.is_empty() {
141 Err(ParseError::InvalidExtension)
142 } else {
143 Ok(Self::from_short_slice_unchecked(ext, keys))
144 }
145 }
146
147 pub fn get_ext_str(&self) -> &str {
159 if true {
if !self.ext.is_ascii_alphabetic() {
::core::panicking::panic("assertion failed: self.ext.is_ascii_alphabetic()")
};
};debug_assert!(self.ext.is_ascii_alphabetic());
160 unsafe { core::str::from_utf8_unchecked(core::slice::from_ref(&self.ext)) }
162 }
163
164 pub fn get_ext(&self) -> char {
176 self.ext as char
177 }
178
179 pub fn get_ext_byte(&self) -> u8 {
191 self.ext
192 }
193
194 pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F, with_ext: bool) -> Result<(), E>
195 where
196 F: FnMut(&str) -> Result<(), E>,
197 {
198 if self.keys.is_empty() {
199 return Ok(());
200 }
201
202 if with_ext {
203 f(self.get_ext_str())?;
204 }
205 self.keys.iter().map(|t| t.as_str()).try_for_each(f)
206 }
207}
208
209#[cfg(feature = "alloc")]
211impl FromStr for Other {
212 type Err = ParseError;
213
214 #[inline]
215 fn from_str(s: &str) -> Result<Self, Self::Err> {
216 Self::try_from_str(s)
217 }
218}
219
220impl core::fmt::Display for Other {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
::writeable::Writeable::write_to(&self, f)
}
}writeable::impl_display_with_writeable!(Other, #[cfg(feature = "alloc")]);
221
222impl writeable::Writeable for Other {
223 fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
224 if self.keys.is_empty() {
225 return Ok(());
226 }
227 sink.write_str(self.get_ext_str())?;
228 for key in self.keys.iter() {
229 sink.write_char('-')?;
230 writeable::Writeable::write_to(key, sink)?;
231 }
232
233 Ok(())
234 }
235
236 fn writeable_length_hint(&self) -> writeable::LengthHint {
237 if self.keys.is_empty() {
238 return writeable::LengthHint::exact(0);
239 };
240 let mut result = writeable::LengthHint::exact(1);
241 for key in self.keys.iter() {
242 result += writeable::Writeable::writeable_length_hint(key) + 1;
243 }
244 result
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251
252 #[test]
253 fn test_other_extension_fromstr() {
254 let oe: Other = "o-foo-bar".parse().expect("Failed to parse Other");
255 assert_eq!(oe.to_string(), "o-foo-bar");
256
257 let oe: Result<Other, _> = "o".parse();
258 assert!(oe.is_err());
259 }
260}