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)]
58pub struct Other {
59 ext: u8,
61 keys: ShortBoxSlice<Subtag>,
62}
63
64impl Other {
65 #[inline]
68 #[cfg(feature = "alloc")]
69 pub fn try_from_str(s: &str) -> Result<Self, ParseError> {
70 Self::try_from_utf8(s.as_bytes())
71 }
72
73 #[cfg(feature = "alloc")]
75 pub fn try_from_utf8(code_units: &[u8]) -> Result<Self, ParseError> {
76 let mut iter = SubtagIterator::new(code_units);
77
78 let ext = iter.next().ok_or(ParseError::InvalidExtension)?;
79 if let ExtensionType::Other(b) = ExtensionType::try_from_byte_slice(ext)? {
80 return Self::try_from_iter(b, &mut iter);
81 }
82
83 Err(ParseError::InvalidExtension)
84 }
85
86 #[cfg(feature = "alloc")]
105 pub fn from_vec_unchecked(ext: u8, keys: Vec<Subtag>) -> Self {
106 Self::from_short_slice_unchecked(ext, keys.into())
107 }
108
109 #[allow(dead_code)]
110 pub(crate) fn from_short_slice_unchecked(ext: u8, keys: ShortBoxSlice<Subtag>) -> Self {
111 if !ext.is_ascii_alphabetic() {
::core::panicking::panic("assertion failed: ext.is_ascii_alphabetic()")
};assert!(ext.is_ascii_alphabetic());
112 Self { ext, keys }
114 }
115
116 #[cfg(feature = "alloc")]
117 pub(crate) fn try_from_iter(ext: u8, iter: &mut SubtagIterator) -> Result<Self, ParseError> {
118 debug_assert!(matches!(
119 ExtensionType::try_from_byte(ext),
120 Ok(ExtensionType::Other(_)),
121 ));
122
123 let mut keys = ShortBoxSlice::new();
124 while let Some(subtag) = iter.peek() {
125 if !Subtag::valid_key(subtag) {
126 break;
127 }
128 if let Ok(key) = Subtag::try_from_utf8(subtag) {
129 keys.push(key);
130 }
131 iter.next();
132 }
133
134 if keys.is_empty() {
135 Err(ParseError::InvalidExtension)
136 } else {
137 Ok(Self::from_short_slice_unchecked(ext, keys))
138 }
139 }
140
141 pub fn get_ext_str(&self) -> &str {
153 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());
154 unsafe { core::str::from_utf8_unchecked(core::slice::from_ref(&self.ext)) }
156 }
157
158 pub fn get_ext(&self) -> char {
170 self.ext as char
171 }
172
173 pub fn get_ext_byte(&self) -> u8 {
185 self.ext
186 }
187
188 pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F, with_ext: bool) -> Result<(), E>
189 where
190 F: FnMut(&str) -> Result<(), E>,
191 {
192 if self.keys.is_empty() {
193 return Ok(());
194 }
195
196 if with_ext {
197 f(self.get_ext_str())?;
198 }
199 self.keys.iter().map(|t| t.as_str()).try_for_each(f)
200 }
201}
202
203#[cfg(feature = "alloc")]
204impl FromStr for Other {
205 type Err = ParseError;
206
207 #[inline]
208 fn from_str(s: &str) -> Result<Self, Self::Err> {
209 Self::try_from_str(s)
210 }
211}
212
213impl core::fmt::Display for Other {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
::writeable::Writeable::write_to(&self, f)
}
}
impl Other {
pub fn to_string(&self) -> ::writeable::_internal::String {
::writeable::Writeable::write_to_string(self).into_owned()
}
}writeable::impl_display_with_writeable!(Other);
214
215impl writeable::Writeable for Other {
216 fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
217 if self.keys.is_empty() {
218 return Ok(());
219 }
220 sink.write_str(self.get_ext_str())?;
221 for key in self.keys.iter() {
222 sink.write_char('-')?;
223 writeable::Writeable::write_to(key, sink)?;
224 }
225
226 Ok(())
227 }
228
229 fn writeable_length_hint(&self) -> writeable::LengthHint {
230 if self.keys.is_empty() {
231 return writeable::LengthHint::exact(0);
232 };
233 let mut result = writeable::LengthHint::exact(1);
234 for key in self.keys.iter() {
235 result += writeable::Writeable::writeable_length_hint(key) + 1;
236 }
237 result
238 }
239
240 #[cfg(feature = "alloc")]
241 fn write_to_string(&self) -> alloc::borrow::Cow<str> {
242 if self.keys.is_empty() {
243 return alloc::borrow::Cow::Borrowed("");
244 }
245 let mut string =
246 alloc::string::String::with_capacity(self.writeable_length_hint().capacity());
247 let _ = self.write_to(&mut string);
248 alloc::borrow::Cow::Owned(string)
249 }
250}
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255
256 #[test]
257 fn test_other_extension_fromstr() {
258 let oe: Other = "o-foo-bar".parse().expect("Failed to parse Other");
259 assert_eq!(oe.to_string(), "o-foo-bar");
260
261 let oe: Result<Other, _> = "o".parse();
262 assert!(oe.is_err());
263 }
264}