• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 use core::borrow::Borrow;
6 use core::iter::FromIterator;
7 use litemap::LiteMap;
8 
9 use super::Key;
10 use super::Value;
11 
12 /// A list of [`Key`]-[`Value`] pairs representing functional information
13 /// about content transformations.
14 ///
15 /// Here are examples of fields used in Unicode:
16 /// - `s0`, `d0` - Transform source/destination
17 /// - `t0` - Machine Translation
18 /// - `h0` - Hybrid Locale Identifiers
19 ///
20 /// You can find the full list in [`Unicode BCP 47 T Extension`] section of LDML.
21 ///
22 /// [`Unicode BCP 47 T Extension`]: https://unicode.org/reports/tr35/tr35.html#BCP47_T_Extension
23 ///
24 /// # Examples
25 ///
26 /// ```
27 /// use icu::locale::extensions::transform::{key, Fields, Value};
28 ///
29 /// let value = "hybrid".parse::<Value>().expect("Failed to parse a Value.");
30 /// let fields = [(key!("h0"), value)].into_iter().collect::<Fields>();
31 ///
32 /// assert_eq!(&fields.to_string(), "h0-hybrid");
33 /// ```
34 #[derive(Clone, PartialEq, Eq, Debug, Default, Hash, PartialOrd, Ord)]
35 pub struct Fields(LiteMap<Key, Value>);
36 
37 impl Fields {
38     /// Returns a new empty list of key-value pairs. Same as [`default()`](Default::default()), but is `const`.
39     ///
40     /// # Examples
41     ///
42     /// ```
43     /// use icu::locale::extensions::transform::Fields;
44     ///
45     /// assert_eq!(Fields::new(), Fields::default());
46     /// ```
47     #[inline]
new() -> Self48     pub const fn new() -> Self {
49         Self(LiteMap::new())
50     }
51 
52     /// Returns `true` if there are no fields.
53     ///
54     /// # Examples
55     ///
56     /// ```
57     /// use icu::locale::locale;
58     /// use icu::locale::Locale;
59     ///
60     /// let loc1 = Locale::try_from_str("und-t-h0-hybrid").unwrap();
61     /// let loc2 = locale!("und-u-ca-buddhist");
62     ///
63     /// assert!(!loc1.extensions.transform.fields.is_empty());
64     /// assert!(loc2.extensions.transform.fields.is_empty());
65     /// ```
is_empty(&self) -> bool66     pub fn is_empty(&self) -> bool {
67         self.0.is_empty()
68     }
69 
70     /// Empties the [`Fields`] list.
71     ///
72     /// Returns the old list.
73     ///
74     /// # Examples
75     ///
76     /// ```
77     /// use icu::locale::extensions::transform::{key, Fields, Value};
78     ///
79     /// let value = "hybrid".parse::<Value>().expect("Failed to parse a Value.");
80     /// let mut fields = [(key!("h0"), value)].into_iter().collect::<Fields>();
81     ///
82     /// assert_eq!(&fields.to_string(), "h0-hybrid");
83     ///
84     /// fields.clear();
85     ///
86     /// assert_eq!(fields, Fields::new());
87     /// ```
clear(&mut self) -> Self88     pub fn clear(&mut self) -> Self {
89         core::mem::take(self)
90     }
91 
92     /// Returns `true` if the list contains a [`Value`] for the specified [`Key`].
93     ///
94     ///
95     /// # Examples
96     ///
97     /// ```
98     /// use icu::locale::extensions::transform::{Fields, Key, Value};
99     ///
100     /// let key: Key = "h0".parse().expect("Failed to parse a Key.");
101     /// let value: Value = "hybrid".parse().expect("Failed to parse a Value.");
102     /// let mut fields = [(key, value)].into_iter().collect::<Fields>();
103     ///
104     /// let key: Key = "h0".parse().expect("Failed to parse a Key.");
105     /// assert!(&fields.contains_key(&key));
106     /// ```
contains_key<Q>(&self, key: &Q) -> bool where Key: Borrow<Q>, Q: Ord,107     pub fn contains_key<Q>(&self, key: &Q) -> bool
108     where
109         Key: Borrow<Q>,
110         Q: Ord,
111     {
112         self.0.contains_key(key)
113     }
114 
115     /// Returns a reference to the [`Value`] corresponding to the [`Key`].
116     ///
117     ///
118     /// # Examples
119     ///
120     /// ```
121     /// use icu::locale::extensions::transform::{key, Fields, Value};
122     ///
123     /// let value = "hybrid".parse::<Value>().unwrap();
124     /// let fields = [(key!("h0"), value.clone())]
125     ///     .into_iter()
126     ///     .collect::<Fields>();
127     ///
128     /// assert_eq!(fields.get(&key!("h0")), Some(&value));
129     /// ```
get<Q>(&self, key: &Q) -> Option<&Value> where Key: Borrow<Q>, Q: Ord,130     pub fn get<Q>(&self, key: &Q) -> Option<&Value>
131     where
132         Key: Borrow<Q>,
133         Q: Ord,
134     {
135         self.0.get(key)
136     }
137 
138     /// Sets the specified keyword, returning the old value if it already existed.
139     ///
140     /// # Examples
141     ///
142     /// ```
143     /// use icu::locale::extensions::transform::{key, Value};
144     /// use icu::locale::Locale;
145     ///
146     /// let lower = "lower".parse::<Value>().expect("valid extension subtag");
147     /// let casefold = "casefold".parse::<Value>().expect("valid extension subtag");
148     ///
149     /// let mut loc: Locale = "en-t-hi-d0-casefold"
150     ///     .parse()
151     ///     .expect("valid BCP-47 identifier");
152     /// let old_value = loc.extensions.transform.fields.set(key!("d0"), lower);
153     ///
154     /// assert_eq!(old_value, Some(casefold));
155     /// assert_eq!(loc, "en-t-hi-d0-lower".parse().unwrap());
156     /// ```
set(&mut self, key: Key, value: Value) -> Option<Value>157     pub fn set(&mut self, key: Key, value: Value) -> Option<Value> {
158         self.0.insert(key, value)
159     }
160 
161     /// Retains a subset of fields as specified by the predicate function.
162     ///
163     /// # Examples
164     ///
165     /// ```
166     /// use icu::locale::extensions::transform::key;
167     /// use icu::locale::Locale;
168     ///
169     /// let mut loc: Locale = "und-t-h0-hybrid-d0-hex-m0-xml".parse().unwrap();
170     ///
171     /// loc.extensions
172     ///     .transform
173     ///     .fields
174     ///     .retain_by_key(|&k| k == key!("h0"));
175     /// assert_eq!(loc, "und-t-h0-hybrid".parse().unwrap());
176     ///
177     /// loc.extensions
178     ///     .transform
179     ///     .fields
180     ///     .retain_by_key(|&k| k == key!("d0"));
181     /// assert_eq!(loc, Locale::default());
182     /// ```
retain_by_key<F>(&mut self, mut predicate: F) where F: FnMut(&Key) -> bool,183     pub fn retain_by_key<F>(&mut self, mut predicate: F)
184     where
185         F: FnMut(&Key) -> bool,
186     {
187         self.0.retain(|k, _| predicate(k))
188     }
189 
for_each_subtag_str<E, F>(&self, f: &mut F) -> Result<(), E> where F: FnMut(&str) -> Result<(), E>,190     pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F) -> Result<(), E>
191     where
192         F: FnMut(&str) -> Result<(), E>,
193     {
194         for (k, v) in self.0.iter() {
195             f(k.as_str())?;
196             v.for_each_subtag_str(f)?;
197         }
198         Ok(())
199     }
200 
201     /// This needs to be its own method to help with type inference in helpers.rs
202     #[cfg(test)]
from_tuple_vec(v: Vec<(Key, Value)>) -> Self203     pub(crate) fn from_tuple_vec(v: Vec<(Key, Value)>) -> Self {
204         v.into_iter().collect()
205     }
206 }
207 
208 impl From<LiteMap<Key, Value>> for Fields {
from(map: LiteMap<Key, Value>) -> Self209     fn from(map: LiteMap<Key, Value>) -> Self {
210         Self(map)
211     }
212 }
213 
214 impl FromIterator<(Key, Value)> for Fields {
from_iter<I: IntoIterator<Item = (Key, Value)>>(iter: I) -> Self215     fn from_iter<I: IntoIterator<Item = (Key, Value)>>(iter: I) -> Self {
216         LiteMap::from_iter(iter).into()
217     }
218 }
219 
220 impl_writeable_for_key_value!(Fields, "h0", "hybrid", "m0", "m0-true");
221