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 crate::ule::AsULE; 6 use crate::ZeroSlice; 7 8 use core::cmp::Ordering; 9 use core::fmt; 10 11 use super::kv::ZeroMapKV; 12 use super::vecs::ZeroVecLike; 13 14 /// A borrowed-only version of [`ZeroMap`](super::ZeroMap) 15 /// 16 /// This is useful for fully-zero-copy deserialization from non-human-readable 17 /// serialization formats. It also has the advantage that it can return references that live for 18 /// the lifetime of the backing buffer as opposed to that of the [`ZeroMapBorrowed`] instance. 19 /// 20 /// # Examples 21 /// 22 /// ``` 23 /// use zerovec::maps::ZeroMapBorrowed; 24 /// 25 /// // Example byte buffer representing the map { 1: "one" } 26 /// let BINCODE_BYTES: &[u8; 25] = &[ 27 /// 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 111, 28 /// 110, 101, 29 /// ]; 30 /// 31 /// // Deserializing to ZeroMap requires no heap allocations. 32 /// let zero_map: ZeroMapBorrowed<u32, str> = 33 /// bincode::deserialize(BINCODE_BYTES) 34 /// .expect("Should deserialize successfully"); 35 /// assert_eq!(zero_map.get(&1), Some("one")); 36 /// ``` 37 /// 38 /// This can be obtained from a [`ZeroMap`](super::ZeroMap) via [`ZeroMap::as_borrowed`](super::ZeroMap::as_borrowed) 39 pub struct ZeroMapBorrowed<'a, K, V> 40 where 41 K: ZeroMapKV<'a>, 42 V: ZeroMapKV<'a>, 43 K: ?Sized, 44 V: ?Sized, 45 { 46 pub(crate) keys: &'a <K as ZeroMapKV<'a>>::Slice, 47 pub(crate) values: &'a <V as ZeroMapKV<'a>>::Slice, 48 } 49 50 impl<'a, K, V> Copy for ZeroMapBorrowed<'a, K, V> 51 where 52 K: ZeroMapKV<'a>, 53 V: ZeroMapKV<'a>, 54 K: ?Sized, 55 V: ?Sized, 56 { 57 } 58 impl<'a, K, V> Clone for ZeroMapBorrowed<'a, K, V> 59 where 60 K: ZeroMapKV<'a>, 61 V: ZeroMapKV<'a>, 62 K: ?Sized, 63 V: ?Sized, 64 { clone(&self) -> Self65 fn clone(&self) -> Self { 66 *self 67 } 68 } 69 70 impl<'a, K, V> Default for ZeroMapBorrowed<'a, K, V> 71 where 72 K: ZeroMapKV<'a>, 73 V: ZeroMapKV<'a>, 74 K::Slice: 'static, 75 V::Slice: 'static, 76 K: ?Sized, 77 V: ?Sized, 78 { default() -> Self79 fn default() -> Self { 80 Self::new() 81 } 82 } 83 84 impl<'a, K, V> ZeroMapBorrowed<'a, K, V> 85 where 86 K: ZeroMapKV<'a>, 87 V: ZeroMapKV<'a>, 88 K::Slice: 'static, 89 V::Slice: 'static, 90 K: ?Sized, 91 V: ?Sized, 92 { 93 /// Creates a new, empty `ZeroMapBorrowed<K, V>`. 94 /// 95 /// Note: Since [`ZeroMapBorrowed`] is not mutable, the return value will be a stub unless 96 /// converted into a [`ZeroMap`](super::ZeroMap). 97 /// 98 /// # Examples 99 /// 100 /// ``` 101 /// use zerovec::maps::ZeroMapBorrowed; 102 /// 103 /// let zm: ZeroMapBorrowed<u16, str> = ZeroMapBorrowed::new(); 104 /// assert!(zm.is_empty()); 105 /// ``` new() -> Self106 pub fn new() -> Self { 107 Self { 108 keys: K::Container::zvl_new_borrowed(), 109 values: V::Container::zvl_new_borrowed(), 110 } 111 } 112 } 113 114 impl<'a, K, V> ZeroMapBorrowed<'a, K, V> 115 where 116 K: ZeroMapKV<'a>, 117 V: ZeroMapKV<'a>, 118 K: ?Sized, 119 V: ?Sized, 120 { 121 #[doc(hidden)] // databake internal from_parts_unchecked( keys: &'a <K as ZeroMapKV<'a>>::Slice, values: &'a <V as ZeroMapKV<'a>>::Slice, ) -> Self122 pub const unsafe fn from_parts_unchecked( 123 keys: &'a <K as ZeroMapKV<'a>>::Slice, 124 values: &'a <V as ZeroMapKV<'a>>::Slice, 125 ) -> Self { 126 Self { keys, values } 127 } 128 129 /// The number of elements in the [`ZeroMapBorrowed`] len(self) -> usize130 pub fn len(self) -> usize { 131 self.values.zvl_len() 132 } 133 134 /// Whether the [`ZeroMapBorrowed`] is empty is_empty(self) -> bool135 pub fn is_empty(self) -> bool { 136 self.values.zvl_len() == 0 137 } 138 } 139 140 impl<'a, K, V> ZeroMapBorrowed<'a, K, V> 141 where 142 K: ZeroMapKV<'a> + Ord, 143 V: ZeroMapKV<'a>, 144 K: ?Sized, 145 V: ?Sized, 146 { 147 /// Get the value associated with `key`, if it exists. 148 /// 149 /// This is able to return values that live longer than the map itself 150 /// since they borrow directly from the backing buffer. This is the 151 /// primary advantage of using [`ZeroMapBorrowed`](super::ZeroMapBorrowed) over [`ZeroMap`](super::ZeroMap). 152 /// 153 /// ```rust 154 /// use zerovec::ZeroMap; 155 /// 156 /// let mut map = ZeroMap::new(); 157 /// map.insert(&1, "one"); 158 /// map.insert(&2, "two"); 159 /// let borrowed = map.as_borrowed(); 160 /// assert_eq!(borrowed.get(&1), Some("one")); 161 /// assert_eq!(borrowed.get(&3), None); 162 /// ``` get(self, key: &K) -> Option<&'a V::GetType>163 pub fn get(self, key: &K) -> Option<&'a V::GetType> { 164 let index = self.keys.zvl_binary_search(key).ok()?; 165 self.values.zvl_get(index) 166 } 167 168 /// Binary search the map with `predicate` to find a key, returning the value. 169 /// 170 /// This is able to return values that live longer than the map itself 171 /// since they borrow directly from the backing buffer. This is the 172 /// primary advantage of using [`ZeroMapBorrowed`](super::ZeroMapBorrowed) over [`ZeroMap`](super::ZeroMap). 173 /// 174 /// ```rust 175 /// use zerovec::ZeroMap; 176 /// 177 /// let mut map = ZeroMap::new(); 178 /// map.insert(&1, "one"); 179 /// map.insert(&2, "two"); 180 /// let borrowed = map.as_borrowed(); 181 /// assert_eq!(borrowed.get_by(|probe| probe.cmp(&1)), Some("one")); 182 /// assert_eq!(borrowed.get_by(|probe| probe.cmp(&3)), None); 183 /// ``` get_by(self, predicate: impl FnMut(&K) -> Ordering) -> Option<&'a V::GetType>184 pub fn get_by(self, predicate: impl FnMut(&K) -> Ordering) -> Option<&'a V::GetType> { 185 let index = self.keys.zvl_binary_search_by(predicate).ok()?; 186 self.values.zvl_get(index) 187 } 188 189 /// Returns whether `key` is contained in this map 190 /// 191 /// ```rust 192 /// use zerovec::ZeroMap; 193 /// 194 /// let mut map = ZeroMap::new(); 195 /// map.insert(&1, "one"); 196 /// map.insert(&2, "two"); 197 /// let borrowed = map.as_borrowed(); 198 /// assert!(borrowed.contains_key(&1)); 199 /// assert!(!borrowed.contains_key(&3)); 200 /// ``` contains_key(self, key: &K) -> bool201 pub fn contains_key(self, key: &K) -> bool { 202 self.keys.zvl_binary_search(key).is_ok() 203 } 204 } 205 206 impl<'a, K, V> ZeroMapBorrowed<'a, K, V> 207 where 208 K: ZeroMapKV<'a> + ?Sized, 209 V: ZeroMapKV<'a> + ?Sized, 210 { 211 /// Produce an ordered iterator over key-value pairs iter( self, ) -> impl Iterator< Item = ( &'a <K as ZeroMapKV<'a>>::GetType, &'a <V as ZeroMapKV<'a>>::GetType, ), >212 pub fn iter( 213 self, 214 ) -> impl Iterator< 215 Item = ( 216 &'a <K as ZeroMapKV<'a>>::GetType, 217 &'a <V as ZeroMapKV<'a>>::GetType, 218 ), 219 > { 220 self.iter_keys().zip(self.iter_values()) 221 } 222 223 /// Produce an ordered iterator over keys iter_keys(self) -> impl Iterator<Item = &'a <K as ZeroMapKV<'a>>::GetType>224 pub fn iter_keys(self) -> impl Iterator<Item = &'a <K as ZeroMapKV<'a>>::GetType> { 225 #[allow(clippy::unwrap_used)] // idx in 0..keys.zvl_len() 226 (0..self.keys.zvl_len()).map(move |idx| self.keys.zvl_get(idx).unwrap()) 227 } 228 229 /// Produce an iterator over values, ordered by keys iter_values(self) -> impl Iterator<Item = &'a <V as ZeroMapKV<'a>>::GetType>230 pub fn iter_values(self) -> impl Iterator<Item = &'a <V as ZeroMapKV<'a>>::GetType> { 231 #[allow(clippy::unwrap_used)] // idx in 0..keys.zvl_len() == values.zvl_len() 232 (0..self.values.zvl_len()).map(move |idx| self.values.zvl_get(idx).unwrap()) 233 } 234 } 235 236 impl<'a, K, V> ZeroMapBorrowed<'a, K, V> 237 where 238 K: ZeroMapKV<'a> + Ord + ?Sized, 239 V: ZeroMapKV<'a, Slice = ZeroSlice<V>> + AsULE + Copy + 'static, 240 { 241 /// For cases when `V` is fixed-size, obtain a direct copy of `V` instead of `V::ULE` get_copied(self, key: &K) -> Option<V>242 pub fn get_copied(self, key: &K) -> Option<V> { 243 let index = self.keys.zvl_binary_search(key).ok()?; 244 self.values.get(index) 245 } 246 247 /// For cases when `V` is fixed-size, obtain a direct copy of `V` instead of `V::ULE` get_copied_by(self, predicate: impl FnMut(&K) -> Ordering) -> Option<V>248 pub fn get_copied_by(self, predicate: impl FnMut(&K) -> Ordering) -> Option<V> { 249 let index = self.keys.zvl_binary_search_by(predicate).ok()?; 250 self.values.get(index) 251 } 252 253 /// Similar to [`Self::iter()`] except it returns a direct copy of the values instead of references 254 /// to `V::ULE`, in cases when `V` is fixed-size iter_copied_values( self, ) -> impl Iterator<Item = (&'a <K as ZeroMapKV<'a>>::GetType, V)>255 pub fn iter_copied_values( 256 self, 257 ) -> impl Iterator<Item = (&'a <K as ZeroMapKV<'a>>::GetType, V)> { 258 (0..self.keys.zvl_len()).map(move |idx| { 259 ( 260 #[allow(clippy::unwrap_used)] // idx in 0..keys.zvl_len() 261 self.keys.zvl_get(idx).unwrap(), 262 #[allow(clippy::unwrap_used)] // idx in 0..keys.zvl_len() = values.zvl_len() 263 self.values.get(idx).unwrap(), 264 ) 265 }) 266 } 267 } 268 269 impl<'a, K, V> ZeroMapBorrowed<'a, K, V> 270 where 271 K: ZeroMapKV<'a, Slice = ZeroSlice<K>> + AsULE + Copy + Ord + 'static, 272 V: ZeroMapKV<'a, Slice = ZeroSlice<V>> + AsULE + Copy + 'static, 273 { 274 /// Similar to [`Self::iter()`] except it returns a direct copy of the keys values instead of references 275 /// to `K::ULE` and `V::ULE`, in cases when `K` and `V` are fixed-size 276 #[allow(clippy::needless_lifetimes)] // Lifetime is necessary in impl Trait iter_copied(self) -> impl Iterator<Item = (K, V)> + 'a277 pub fn iter_copied(self) -> impl Iterator<Item = (K, V)> + 'a { 278 let len = self.keys.zvl_len(); 279 (0..len).map(move |idx| { 280 ( 281 #[allow(clippy::unwrap_used)] // idx in 0..keys.zvl_len() 282 ZeroSlice::get(self.keys, idx).unwrap(), 283 #[allow(clippy::unwrap_used)] // idx in 0..keys.zvl_len() = values.zvl_len() 284 ZeroSlice::get(self.values, idx).unwrap(), 285 ) 286 }) 287 } 288 } 289 290 // We can't use the default PartialEq because ZeroMap is invariant 291 // so otherwise rustc will not automatically allow you to compare ZeroMaps 292 // with different lifetimes 293 impl<'a, 'b, K, V> PartialEq<ZeroMapBorrowed<'b, K, V>> for ZeroMapBorrowed<'a, K, V> 294 where 295 K: for<'c> ZeroMapKV<'c> + ?Sized, 296 V: for<'c> ZeroMapKV<'c> + ?Sized, 297 <K as ZeroMapKV<'a>>::Slice: PartialEq<<K as ZeroMapKV<'b>>::Slice>, 298 <V as ZeroMapKV<'a>>::Slice: PartialEq<<V as ZeroMapKV<'b>>::Slice>, 299 { eq(&self, other: &ZeroMapBorrowed<'b, K, V>) -> bool300 fn eq(&self, other: &ZeroMapBorrowed<'b, K, V>) -> bool { 301 self.keys.eq(other.keys) && self.values.eq(other.values) 302 } 303 } 304 305 impl<'a, K, V> fmt::Debug for ZeroMapBorrowed<'a, K, V> 306 where 307 K: ZeroMapKV<'a> + ?Sized, 308 V: ZeroMapKV<'a> + ?Sized, 309 K::Slice: fmt::Debug, 310 V::Slice: fmt::Debug, 311 { fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 313 f.debug_struct("ZeroMapBorrowed") 314 .field("keys", &self.keys) 315 .field("values", &self.values) 316 .finish() 317 } 318 } 319