icu_locale_core/extensions/unicode/
value.rs1use crate::parser::ParseError;
6use crate::parser::SubtagIterator;
7use crate::shortvec::{ShortBoxSlice, ShortBoxSliceIntoIter};
8use crate::subtags::{subtag, Subtag};
9#[cfg(feature = "alloc")]
10use alloc::vec::Vec;
11#[cfg(feature = "alloc")]
12use core::str::FromStr;
13
14#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Value {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Value",
&&self.0)
}
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for Value {
#[inline]
fn eq(&self, other: &Value) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Value {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<ShortBoxSlice<Subtag>>;
}
}Eq, #[automatically_derived]
impl ::core::clone::Clone for Value {
#[inline]
fn clone(&self) -> Value { Value(::core::clone::Clone::clone(&self.0)) }
}Clone, #[automatically_derived]
impl ::core::hash::Hash for Value {
#[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 Value {
#[inline]
fn partial_cmp(&self, other: &Value)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for Value {
#[inline]
fn cmp(&self, other: &Value) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}Ord, #[automatically_derived]
impl ::core::default::Default for Value {
#[inline]
fn default() -> Value { Value(::core::default::Default::default()) }
}Default)]
38pub struct Value(ShortBoxSlice<Subtag>);
39
40const TRUE_VALUE: Subtag = const {
use crate::subtags::Subtag;
match Subtag::try_from_utf8("true".as_bytes()) {
Ok(r) => r,
_ => {
::core::panicking::panic_fmt(format_args!("Invalid subtags::Subtag: true"));
}
}
}subtag!("true");
41
42impl Value {
43 #[inline]
60 pub fn try_from_str(s: &str) -> Result<Self, ParseError> {
61 Self::try_from_utf8(s.as_bytes())
62 }
63
64 pub fn try_from_utf8(code_units: &[u8]) -> Result<Self, ParseError> {
66 let mut v = ShortBoxSlice::new();
67
68 if !code_units.is_empty() {
69 for chunk in SubtagIterator::new(code_units) {
70 let subtag = Subtag::try_from_utf8(chunk)?;
71 if subtag != TRUE_VALUE {
72 #[cfg(feature = "alloc")]
73 v.push(subtag);
74 #[cfg(not(feature = "alloc"))]
75 if v.is_empty() {
76 v = ShortBoxSlice::new_single(subtag);
77 } else if let &[prev] = &*v {
78 v = ShortBoxSlice::new_double(prev, subtag);
79 } else {
80 return Err(ParseError::InvalidSubtag);
81 }
82 }
83 }
84 }
85 Ok(Self(v))
86 }
87
88 pub const fn as_single_subtag(&self) -> Option<&Subtag> {
104 self.0.single()
105 }
106
107 pub fn into_single_subtag(self) -> Option<Subtag> {
123 self.0.into_single()
124 }
125
126 #[doc(hidden)]
127 pub fn as_subtags_slice(&self) -> &[Subtag] {
128 &self.0
129 }
130
131 #[cfg(feature = "alloc")]
146 pub fn push_subtag(&mut self, subtag: Subtag) {
147 self.0.push(subtag);
148 }
149
150 pub fn subtag_count(&self) -> usize {
163 self.0.len()
164 }
165
166 pub const fn new_empty() -> Self {
176 Self(ShortBoxSlice::new())
177 }
178
179 pub fn is_empty(&self) -> bool {
190 self.0.is_empty()
191 }
192
193 pub fn remove_subtag(&mut self, idx: usize) -> Option<Subtag> {
209 if self.0.len() < idx {
210 None
211 } else {
212 let item = self.0.remove(idx);
213 Some(item)
214 }
215 }
216
217 pub fn get_subtag(&self, idx: usize) -> Option<&Subtag> {
232 self.0.get(idx)
233 }
234
235 #[doc(hidden)]
236 pub const fn from_subtag(subtag: Option<Subtag>) -> Self {
237 match subtag {
238 None | Some(TRUE_VALUE) => Self(ShortBoxSlice::new()),
239 Some(val) => Self(ShortBoxSlice::new_single(val)),
240 }
241 }
242
243 #[doc(hidden)]
244 pub fn from_two_subtags(f: Subtag, s: Subtag) -> Self {
245 Self(ShortBoxSlice::new_double(f, s))
246 }
247
248 #[cfg(feature = "alloc")]
271 pub fn from_vec_unchecked(input: Vec<Subtag>) -> Self {
272 Self(input.into())
273 }
274
275 #[allow(dead_code)]
276 pub(crate) fn from_short_slice_unchecked(input: ShortBoxSlice<Subtag>) -> Self {
277 Self(input)
278 }
279
280 pub(crate) const fn parse_subtag_from_utf8(t: &[u8]) -> Result<Option<Subtag>, ParseError> {
281 match Subtag::try_from_utf8(t) {
282 Ok(TRUE_VALUE) => Ok(None),
283 Ok(s) => Ok(Some(s)),
284 Err(_) => Err(ParseError::InvalidSubtag),
285 }
286 }
287
288 pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F) -> Result<(), E>
289 where
290 F: FnMut(&str) -> Result<(), E>,
291 {
292 self.0.iter().map(Subtag::as_str).try_for_each(f)
293 }
294}
295
296impl IntoIterator for Value {
297 type Item = Subtag;
298
299 type IntoIter = ShortBoxSliceIntoIter<Subtag>;
300
301 fn into_iter(self) -> Self::IntoIter {
302 self.0.into_iter()
303 }
304}
305
306#[cfg(feature = "alloc")]
308impl FromIterator<Subtag> for Value {
309 fn from_iter<T: IntoIterator<Item = Subtag>>(iter: T) -> Self {
310 Self(ShortBoxSlice::from_iter(iter))
311 }
312}
313
314#[cfg(feature = "alloc")]
316impl Extend<Subtag> for Value {
317 fn extend<T: IntoIterator<Item = Subtag>>(&mut self, iter: T) {
318 for i in iter {
319 self.0.push(i);
320 }
321 }
322}
323
324#[cfg(feature = "alloc")]
326impl FromStr for Value {
327 type Err = ParseError;
328
329 #[inline]
330 fn from_str(s: &str) -> Result<Self, Self::Err> {
331 Self::try_from_str(s)
332 }
333}
334
335impl PartialEq<&str> for Value {
336 fn eq(&self, other: &&str) -> bool {
337 writeable::cmp_utf8(self, other.as_bytes()).is_eq()
338 }
339}
340
341impl writeable::Writeable for Value {
fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W)
-> core::fmt::Result {
let mut initial = true;
self.for_each_subtag_str(&mut |subtag|
{
if initial {
initial = false;
} else { sink.write_char('-')?; }
sink.write_str(subtag)
})
}
#[inline]
fn writeable_length_hint(&self) -> writeable::LengthHint {
let mut result = writeable::LengthHint::exact(0);
let mut initial = true;
self.for_each_subtag_str::<core::convert::Infallible,
_>(&mut |subtag|
{
if initial { initial = false; } else { result += 1; }
result += subtag.len();
Ok(())
}).expect("infallible");
result
}
fn writeable_borrow(&self) -> Option<&str> {
let selff = self;
if selff.0.len() == 1 {
#[allow(clippy :: unwrap_used)]
{ Some(selff.0.get(0).unwrap().as_str()) }
} else { None }
}
}
impl core::fmt::Display for Value {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
::writeable::Writeable::write_to(&self, f)
}
}impl_writeable_for_subtag_list!(Value, "islamic", "civil");
342
343#[macro_export]
363#[doc(hidden)] macro_rules! extensions_unicode_value {
365 ($value:literal) => {
366 const {
367 $crate::extensions::unicode::Value::from_subtag(
368 match $crate::subtags::Subtag::try_from_utf8($value.as_bytes()) {
369 Ok(r) => Some(r),
370 _ => panic!(concat!("Invalid Unicode extension value: ", $value)),
371 },
372 )
373 }
374 };
375}
376#[doc(inline)]
377pub use extensions_unicode_value as value;