1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use super::Variant;
6use crate::helpers::ShortSlice;
7
8use alloc::vec::Vec;
9use core::ops::Deref;
10
11/// A list of variants (examples: `["macos", "posix"]`, etc.)
12///
13/// [`Variants`] stores a list of [`Variant`] subtags in a canonical form
14/// by sorting and deduplicating them.
15///
16/// # Examples
17///
18/// ```
19/// use icu::locid::subtags::{variant, Variants};
20///
21/// let mut v = vec![variant!("posix"), variant!("macos")];
22/// v.sort();
23/// v.dedup();
24///
25/// let variants: Variants = Variants::from_vec_unchecked(v);
26/// assert_eq!(variants.to_string(), "macos-posix");
27/// ```
28#[derive(Default, Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
29pub struct Variants(ShortSlice<Variant>);
30
31impl Variants {
32 /// Returns a new empty list of variants. Same as [`default()`](Default::default()), but is `const`.
33 ///
34 /// # Examples
35 ///
36 /// ```
37 /// use icu::locid::subtags::Variants;
38 ///
39 /// assert_eq!(Variants::new(), Variants::default());
40 /// ```
41 #[inline]
42 pub const fn new() -> Self {
43 Self(ShortSlice::new())
44 }
45
46 /// Creates a new [`Variants`] set from a single [`Variant`].
47 ///
48 /// # Examples
49 ///
50 /// ```
51 /// use icu::locid::subtags::{variant, Variants};
52 ///
53 /// let variants = Variants::from_variant(variant!("posix"));
54 /// ```
55 #[inline]
56 pub const fn from_variant(variant: Variant) -> Self {
57 Self(ShortSlice::new_single(variant))
58 }
59
60 /// Creates a new [`Variants`] set from a [`Vec`].
61 /// The caller is expected to provide sorted and deduplicated vector as
62 /// an input.
63 ///
64 /// # Examples
65 ///
66 /// ```
67 /// use icu::locid::subtags::{variant, Variants};
68 ///
69 /// let mut v = vec![variant!("posix"), variant!("macos")];
70 /// v.sort();
71 /// v.dedup();
72 ///
73 /// let variants = Variants::from_vec_unchecked(v);
74 /// ```
75 ///
76 /// Notice: For performance- and memory-constrained environments, it is recommended
77 /// for the caller to use [`binary_search`](slice::binary_search) instead of [`sort`](slice::sort)
78 /// and [`dedup`](Vec::dedup()).
79 pub fn from_vec_unchecked(input: Vec<Variant>) -> Self {
80 Self(input.into())
81 }
82
83 pub(crate) fn from_short_slice_unchecked(input: ShortSlice<Variant>) -> Self {
84 Self(input)
85 }
86
87 /// Empties the [`Variants`] list.
88 ///
89 /// Returns the old list.
90 ///
91 /// # Examples
92 ///
93 /// ```
94 /// use icu::locid::subtags::{variant, Variants};
95 ///
96 /// let mut v = vec![variant!("posix"), variant!("macos")];
97 /// v.sort();
98 /// v.dedup();
99 ///
100 /// let mut variants: Variants = Variants::from_vec_unchecked(v);
101 ///
102 /// assert_eq!(variants.to_string(), "macos-posix");
103 ///
104 /// variants.clear();
105 ///
106 /// assert_eq!(variants, Variants::default());
107 /// ```
108 pub fn clear(&mut self) -> Self {
109 core::mem::take(self)
110 }
111
112 pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F) -> Result<(), E>
113 where
114 F: FnMut(&str) -> Result<(), E>,
115 {
116 self.deref().iter().map(|t| t.as_str()).try_for_each(f)
117 }
118}
119
120impl_writeable_for_subtag_list!(Variants, "macos", "posix");
121
122impl Deref for Variants {
123 type Target = [Variant];
124
125 fn deref(&self) -> &[Variant] {
126 self.0.deref()
127 }
128}
129