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