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_fields_are_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")]
148 pub fn push_subtag(&mut self, subtag: Subtag) {
149 if subtag != TRUE_VALUE {
150 self.0.push(subtag);
151 }
152 }
153
154 pub fn subtag_count(&self) -> usize {
167 self.0.len()
168 }
169
170 pub const fn new_empty() -> Self {
180 Self(ShortBoxSlice::new())
181 }
182
183 pub fn is_empty(&self) -> bool {
194 self.0.is_empty()
195 }
196
197 pub fn remove_subtag(&mut self, idx: usize) -> Option<Subtag> {
213 if self.0.len() < idx {
214 None
215 } else {
216 let item = self.0.remove(idx);
217 Some(item)
218 }
219 }
220
221 pub fn get_subtag(&self, idx: usize) -> Option<&Subtag> {
236 self.0.get(idx)
237 }
238
239 #[doc(hidden)]
240 pub const fn from_subtag(subtag: Option<Subtag>) -> Self {
241 match subtag {
242 None | Some(TRUE_VALUE) => Self(ShortBoxSlice::new()),
243 Some(val) => Self(ShortBoxSlice::new_single(val)),
244 }
245 }
246
247 #[doc(hidden)]
248 pub fn from_two_subtags(f: Subtag, s: Subtag) -> Self {
249 Self(ShortBoxSlice::new_double(f, s))
250 }
251
252 #[cfg(feature = "alloc")]
275 pub fn from_vec_unchecked(input: Vec<Subtag>) -> Self {
276 Self(input.into())
277 }
278
279 #[allow(dead_code)]
280 pub(crate) fn from_short_slice_unchecked(input: ShortBoxSlice<Subtag>) -> Self {
281 Self(input)
282 }
283
284 pub(crate) const fn parse_subtag_from_utf8(t: &[u8]) -> Result<Option<Subtag>, ParseError> {
285 match Subtag::try_from_utf8(t) {
286 Ok(TRUE_VALUE) => Ok(None),
287 Ok(s) => Ok(Some(s)),
288 Err(_) => Err(ParseError::InvalidSubtag),
289 }
290 }
291
292 pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F) -> Result<(), E>
293 where
294 F: FnMut(&str) -> Result<(), E>,
295 {
296 self.0.iter().map(Subtag::as_str).try_for_each(f)
297 }
298}
299
300impl IntoIterator for Value {
301 type Item = Subtag;
302
303 type IntoIter = ShortBoxSliceIntoIter<Subtag>;
304
305 fn into_iter(self) -> Self::IntoIter {
306 self.0.into_iter()
307 }
308}
309
310#[cfg(feature = "alloc")]
312impl FromIterator<Subtag> for Value {
313 fn from_iter<T: IntoIterator<Item = Subtag>>(iter: T) -> Self {
314 Self(ShortBoxSlice::from_iter(iter))
315 }
316}
317
318#[cfg(feature = "alloc")]
320impl Extend<Subtag> for Value {
321 fn extend<T: IntoIterator<Item = Subtag>>(&mut self, iter: T) {
322 for i in iter {
323 self.0.push(i);
324 }
325 }
326}
327
328#[cfg(feature = "alloc")]
330impl FromStr for Value {
331 type Err = ParseError;
332
333 #[inline]
334 fn from_str(s: &str) -> Result<Self, Self::Err> {
335 Self::try_from_str(s)
336 }
337}
338
339impl PartialEq<&str> for Value {
340 fn eq(&self, other: &&str) -> bool {
341 writeable::cmp_utf8(self, other.as_bytes()).is_eq()
342 }
343}
344
345impl 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");
346
347#[macro_export]
367#[doc(hidden)] macro_rules! extensions_unicode_value {
369 ($value:literal) => {
370 const {
371 $crate::extensions::unicode::Value::from_subtag(
372 match $crate::subtags::Subtag::try_from_utf8($value.as_bytes()) {
373 Ok(r) => Some(r),
374 _ => panic!(concat!("Invalid Unicode extension value: ", $value)),
375 },
376 )
377 }
378 };
379}
380#[doc(inline)]
381pub use extensions_unicode_value as value;