icu_locale_core/extensions/private/
mod.rs1mod other;
31
32#[cfg(feature = "alloc")]
33use alloc::vec::Vec;
34use core::ops::Deref;
35#[cfg(feature = "alloc")]
36use core::str::FromStr;
37
38#[doc(inline)]
39pub use other::{subtag, Subtag};
40
41#[cfg(feature = "alloc")]
42use super::ExtensionType;
43#[cfg(feature = "alloc")]
44use crate::parser::ParseError;
45#[cfg(feature = "alloc")]
46use crate::parser::SubtagIterator;
47use crate::shortvec::ShortBoxSlice;
48
49pub(crate) const PRIVATE_EXT_CHAR: char = 'x';
50pub(crate) const PRIVATE_EXT_STR: &str = "x";
51
52#[derive(#[automatically_derived]
impl ::core::clone::Clone for Private {
#[inline]
fn clone(&self) -> Private {
Private(::core::clone::Clone::clone(&self.0))
}
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for Private {
#[inline]
fn eq(&self, other: &Private) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Private {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<ShortBoxSlice<Subtag>>;
}
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for Private {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Private",
&&self.0)
}
}Debug, #[automatically_derived]
impl ::core::default::Default for Private {
#[inline]
fn default() -> Private { Private(::core::default::Default::default()) }
}Default, #[automatically_derived]
impl ::core::hash::Hash for Private {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.0, state)
}
}Hash, #[automatically_derived]
impl ::core::cmp::PartialOrd for Private {
#[inline]
fn partial_cmp(&self, other: &Private)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for Private {
#[inline]
fn cmp(&self, other: &Private) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}Ord)]
73pub struct Private(ShortBoxSlice<Subtag>);
74
75impl Private {
76 #[inline]
86 pub const fn new() -> Self {
87 Self(ShortBoxSlice::new())
88 }
89
90 #[inline]
95 #[cfg(feature = "alloc")]
96 pub fn try_from_str(s: &str) -> Result<Self, ParseError> {
97 Self::try_from_utf8(s.as_bytes())
98 }
99
100 #[cfg(feature = "alloc")]
104 pub fn try_from_utf8(code_units: &[u8]) -> Result<Self, ParseError> {
105 let mut iter = SubtagIterator::new(code_units);
106
107 let ext = iter.next().ok_or(ParseError::InvalidExtension)?;
108 if let ExtensionType::Private = ExtensionType::try_from_byte_slice(ext)? {
109 return Self::try_from_iter(&mut iter);
110 }
111
112 Err(ParseError::InvalidExtension)
113 }
114
115 #[cfg(feature = "alloc")]
131 pub fn from_vec_unchecked(input: Vec<Subtag>) -> Self {
132 Self(input.into())
133 }
134
135 pub const fn new_single(input: Subtag) -> Self {
148 Self(ShortBoxSlice::new_single(input))
149 }
150
151 pub fn clear(&mut self) {
169 self.0.clear();
170 }
171
172 #[cfg(feature = "alloc")]
173 pub(crate) fn try_from_iter(iter: &mut SubtagIterator) -> Result<Self, ParseError> {
174 let keys = iter
175 .map(Subtag::try_from_utf8)
176 .collect::<Result<ShortBoxSlice<_>, _>>()?;
177
178 if keys.is_empty() {
179 Err(ParseError::InvalidExtension)
180 } else {
181 Ok(Self(keys))
182 }
183 }
184
185 pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F, with_ext: bool) -> Result<(), E>
186 where
187 F: FnMut(&str) -> Result<(), E>,
188 {
189 if self.is_empty() {
190 return Ok(());
191 }
192 if with_ext {
193 f(PRIVATE_EXT_STR)?;
194 }
195 self.deref().iter().map(|t| t.as_str()).try_for_each(f)
196 }
197}
198
199#[cfg(feature = "alloc")]
201impl FromStr for Private {
202 type Err = ParseError;
203
204 #[inline]
205 fn from_str(s: &str) -> Result<Self, Self::Err> {
206 Self::try_from_str(s)
207 }
208}
209
210impl core::fmt::Display for Private {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
::writeable::Writeable::write_to(&self, f)
}
}writeable::impl_display_with_writeable!(Private, #[cfg(feature = "alloc")]);
211
212impl writeable::Writeable for Private {
213 fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
214 if self.is_empty() {
215 return Ok(());
216 }
217 sink.write_char(PRIVATE_EXT_CHAR)?;
218 for key in self.iter() {
219 sink.write_char('-')?;
220 writeable::Writeable::write_to(key, sink)?;
221 }
222 Ok(())
223 }
224
225 fn writeable_length_hint(&self) -> writeable::LengthHint {
226 if self.is_empty() {
227 return writeable::LengthHint::exact(0);
228 }
229 let mut result = writeable::LengthHint::exact(1);
230 for key in self.iter() {
231 result += writeable::Writeable::writeable_length_hint(key) + 1;
232 }
233 result
234 }
235}
236
237impl Deref for Private {
238 type Target = [Subtag];
239
240 fn deref(&self) -> &Self::Target {
241 self.0.deref()
242 }
243}
244
245#[cfg(test)]
246mod tests {
247 use super::*;
248
249 #[test]
250 fn test_private_extension_fromstr() {
251 let pe: Private = "x-foo-bar-l-baz".parse().expect("Failed to parse Private");
252 assert_eq!(pe.to_string(), "x-foo-bar-l-baz");
253
254 let pe: Result<Private, _> = "x".parse();
255 assert!(pe.is_err());
256 }
257}