musli_zerocopy/phf/
map.rs

1//! A map which implements a hash-map like interface, where values can be looked
2//! up by keys.
3//!
4//! This map are implemented using a perfect hash functions, and are inserted
5//! into a buffering using [`phf::store_map`].
6//!
7//! There's two types provided by this module:
8//! * [`Map<K, V>`] which is a *bound* reference to a map, providing a
9//!   convenient map-like access.
10//! * [`MapRef<K, V>`] which is the *pointer* of the map. This is what you store
11//!   in [`ZeroCopy`] types and is what is returned by [`phf::store_map`].
12//!
13//! [`phf::store_map`]: crate::phf::store_map
14
15use core::borrow::Borrow;
16use core::hash::Hash;
17
18use crate::buf::{Bindable, Buf, Visit};
19use crate::endian::{ByteOrder, Native};
20use crate::error::Error;
21use crate::phf::Entry;
22use crate::phf::hashing::HashKey;
23use crate::pointer::{DefaultSize, Ref, Size};
24use crate::{Endian, ZeroCopy};
25
26/// A map bound to a [`Buf`] through [`Buf::bind`] for convenience.
27///
28/// ## Examples
29///
30/// ```
31/// use musli_zerocopy::OwnedBuf;
32/// use musli_zerocopy::phf;
33///
34/// let mut buf = OwnedBuf::new();
35///
36/// let map = phf::store_map(&mut buf, [(1, 2), (2, 3)])?;
37/// let map = buf.bind(map)?;
38///
39/// assert_eq!(map.get(&1)?, Some(&2));
40/// assert_eq!(map.get(&2)?, Some(&3));
41/// assert_eq!(map.get(&3)?, None);
42///
43/// assert!(map.contains_key(&1)?);
44/// assert!(!map.contains_key(&3)?);
45/// # Ok::<_, musli_zerocopy::Error>(())
46/// ```
47pub struct Map<'a, K, V> {
48    key: HashKey,
49    entries: &'a [Entry<K, V>],
50    displacements: &'a [Entry<u32, u32>],
51    buf: &'a Buf,
52}
53
54impl<K, V> Map<'_, K, V>
55where
56    K: ZeroCopy,
57    V: ZeroCopy,
58{
59    /// Get a value from the map.
60    ///
61    /// ## Examples
62    ///
63    /// ```
64    /// use musli_zerocopy::OwnedBuf;
65    /// use musli_zerocopy::phf;
66    ///
67    /// let mut buf = OwnedBuf::new();
68    ///
69    /// let map = phf::store_map(&mut buf, [(1, 2), (2, 3)])?;
70    /// let map = buf.bind(map)?;
71    ///
72    /// assert_eq!(map.get(&1)?, Some(&2));
73    /// assert_eq!(map.get(&2)?, Some(&3));
74    /// assert_eq!(map.get(&3)?, None);
75    /// # Ok::<_, musli_zerocopy::Error>(())
76    /// ```
77    pub fn get<T>(&self, key: &T) -> Result<Option<&V>, Error>
78    where
79        T: ?Sized + Visit,
80        T::Target: Eq + Hash,
81        K: Visit,
82        K::Target: Borrow<T::Target>,
83    {
84        let Some(entry) = self.get_entry(key)? else {
85            return Ok(None);
86        };
87
88        Ok(Some(entry.1))
89    }
90
91    /// Test if the map contains the given `key`.
92    ///
93    /// ## Examples
94    ///
95    /// ```
96    /// use musli_zerocopy::OwnedBuf;
97    /// use musli_zerocopy::phf;
98    ///
99    /// let mut buf = OwnedBuf::new();
100    ///
101    /// let map = phf::store_map(&mut buf, [(1, 2), (2, 3)])?;
102    /// let map = buf.bind(map)?;
103    ///
104    /// assert!(map.contains_key(&1)?);
105    /// assert!(map.contains_key(&2)?);
106    /// assert!(!map.contains_key(&3)?);
107    /// # Ok::<_, musli_zerocopy::Error>(())
108    /// ```
109    pub fn contains_key<T>(&self, key: &T) -> Result<bool, Error>
110    where
111        T: ?Sized + Visit,
112        T::Target: Eq + Hash,
113        K: Visit,
114        K::Target: Borrow<T::Target>,
115    {
116        Ok(self.get_entry(key)?.is_some())
117    }
118
119    /// Get an entry from the map.
120    ///
121    /// ## Examples
122    ///
123    /// ```
124    /// use musli_zerocopy::OwnedBuf;
125    /// use musli_zerocopy::phf;
126    ///
127    /// let mut buf = OwnedBuf::new();
128    ///
129    /// let map = phf::store_map(&mut buf, [(1, 2), (2, 3)])?;
130    /// let map = buf.bind(map)?;
131    ///
132    /// assert_eq!(map.get_entry(&1)?, Some((&1, &2)));
133    /// assert_eq!(map.get_entry(&2)?, Some((&2, &3)));
134    /// assert_eq!(map.get_entry(&3)?, None);
135    /// # Ok::<_, musli_zerocopy::Error>(())
136    /// ```
137    pub fn get_entry<T>(&self, key: &T) -> Result<Option<(&K, &V)>, Error>
138    where
139        T: ?Sized + Visit,
140        T::Target: Eq + Hash,
141        K: Visit,
142        K::Target: Borrow<T::Target>,
143    {
144        if self.displacements.is_empty() {
145            return Ok(None);
146        }
147
148        let hashes = crate::phf::hashing::hash(self.buf, key, &self.key)?;
149        let index =
150            crate::phf::hashing::get_index(&hashes, self.displacements, self.entries.len())?;
151
152        let Some(e) = self.entries.get(index) else {
153            return Ok(None);
154        };
155
156        if key.visit(self.buf, |b| e.key.visit(self.buf, |a| a.borrow() == b))?? {
157            Ok(Some((&e.key, &e.value)))
158        } else {
159            Ok(None)
160        }
161    }
162}
163
164/// Bind a [`MapRef`] into a [`Map`].
165impl<K, V, E, O> Bindable for MapRef<K, V, E, O>
166where
167    K: ZeroCopy,
168    V: ZeroCopy,
169    E: ByteOrder,
170    O: Size,
171{
172    type Bound<'a>
173        = Map<'a, K, V>
174    where
175        Self: 'a;
176
177    #[inline]
178    fn bind(self, buf: &Buf) -> Result<Self::Bound<'_>, Error> {
179        Ok(Map {
180            key: self.key.to_ne(),
181            entries: buf.load(self.entries)?,
182            displacements: buf.load(self.displacements)?,
183            buf,
184        })
185    }
186}
187
188/// A stored reference to a map.
189///
190/// Note that operating over the methods provided in [`MapRef`] does not demand
191/// that the entire contents of the set is validated as would be the case when
192/// [`bind()`] is used and might result in better performance if the data is
193/// infrequently accessed.
194///
195/// Constructed through [`phf::store_map`].
196///
197/// [`phf::store_map`]: crate::phf::store_map
198/// [`bind()`]: crate::buf::Buf::bind
199///
200/// ## Examples
201///
202/// ```
203/// use musli_zerocopy::OwnedBuf;
204/// use musli_zerocopy::phf;
205///
206/// let mut buf = OwnedBuf::new();
207///
208/// let map = phf::store_map(&mut buf, [(1, 2), (2, 3)])?;
209///
210/// assert_eq!(map.get(&buf, &1)?, Some(&2));
211/// assert_eq!(map.get(&buf, &2)?, Some(&3));
212/// assert_eq!(map.get(&buf, &3)?, None);
213///
214/// assert!(map.contains_key(&buf, &1)?);
215/// assert!(!map.contains_key(&buf, &3)?);
216/// # Ok::<_, musli_zerocopy::Error>(())
217/// ```
218#[derive(Debug, ZeroCopy)]
219#[repr(C)]
220#[zero_copy(crate)]
221pub struct MapRef<K, V, E = Native, O = DefaultSize>
222where
223    K: ZeroCopy,
224    V: ZeroCopy,
225    E: ByteOrder,
226    O: Size,
227{
228    key: Endian<HashKey, E>,
229    entries: Ref<[Entry<K, V>], E, O>,
230    displacements: Ref<[Entry<u32, u32>], E, O>,
231}
232
233impl<K, V, E, O> MapRef<K, V, E, O>
234where
235    K: ZeroCopy,
236    V: ZeroCopy,
237    E: ByteOrder,
238    O: Size,
239{
240    #[cfg(feature = "alloc")]
241    pub(crate) fn new(
242        key: HashKey,
243        entries: Ref<[Entry<K, V>], E, O>,
244        displacements: Ref<[Entry<u32, u32>], E, O>,
245    ) -> Self {
246        Self {
247            key: Endian::new(key),
248            entries,
249            displacements,
250        }
251    }
252}
253
254impl<K, V, E, O> MapRef<K, V, E, O>
255where
256    K: ZeroCopy,
257    V: ZeroCopy,
258    E: ByteOrder,
259    O: Size,
260{
261    /// Get a value from the map.
262    ///
263    /// ## Examples
264    ///
265    /// ```
266    /// use musli_zerocopy::OwnedBuf;
267    /// use musli_zerocopy::phf;
268    ///
269    /// let mut buf = OwnedBuf::new();
270    ///
271    /// let map = phf::store_map(&mut buf, [(1, 2), (2, 3)])?;
272    ///
273    /// assert_eq!(map.get(&buf, &1)?, Some(&2));
274    /// assert_eq!(map.get(&buf, &2)?, Some(&3));
275    /// assert_eq!(map.get(&buf, &3)?, None);
276    /// # Ok::<_, musli_zerocopy::Error>(())
277    /// ```
278    pub fn get<'a, T>(&self, buf: &'a Buf, key: &T) -> Result<Option<&'a V>, Error>
279    where
280        T: ?Sized + Visit,
281        T::Target: Eq + Hash,
282        K: 'a + Visit,
283        K::Target: Borrow<T::Target>,
284    {
285        let Some(entry) = self.get_entry(buf, key)? else {
286            return Ok(None);
287        };
288
289        Ok(Some(entry.1))
290    }
291
292    /// Test if the map contains the given `key`.
293    ///
294    /// ## Examples
295    ///
296    /// ```
297    /// use musli_zerocopy::OwnedBuf;
298    /// use musli_zerocopy::phf;
299    ///
300    /// let mut buf = OwnedBuf::new();
301    ///
302    /// let map = phf::store_map(&mut buf, [(1, 2), (2, 3)])?;
303    ///
304    /// assert!(map.contains_key(&buf, &1)?);
305    /// assert!(map.contains_key(&buf, &2)?);
306    /// assert!(!map.contains_key(&buf, &3)?);
307    /// # Ok::<_, musli_zerocopy::Error>(())
308    /// ```
309    pub fn contains_key<T>(&self, buf: &Buf, key: &T) -> Result<bool, Error>
310    where
311        T: ?Sized + Visit,
312        T::Target: Eq + Hash,
313        K: Visit,
314        K::Target: Borrow<T::Target>,
315    {
316        Ok(self.get_entry(buf, key)?.is_some())
317    }
318
319    /// Get an entry from the map.
320    ///
321    /// ## Examples
322    ///
323    /// ```
324    /// use musli_zerocopy::OwnedBuf;
325    /// use musli_zerocopy::phf;
326    ///
327    /// let mut buf = OwnedBuf::new();
328    ///
329    /// let map = phf::store_map(&mut buf, [(1, 2), (2, 3)])?;
330    ///
331    /// assert_eq!(map.get_entry(&buf, &1)?, Some((&1, &2)));
332    /// assert_eq!(map.get_entry(&buf, &2)?, Some((&2, &3)));
333    /// assert_eq!(map.get_entry(&buf, &3)?, None);
334    /// # Ok::<_, musli_zerocopy::Error>(())
335    /// ```
336    pub fn get_entry<'a, T>(&self, buf: &'a Buf, key: &T) -> Result<Option<(&'a K, &'a V)>, Error>
337    where
338        T: ?Sized + Visit,
339        T::Target: Eq + Hash,
340        K: 'a + Visit,
341        K::Target: Borrow<T::Target>,
342    {
343        if self.displacements.is_empty() {
344            return Ok(None);
345        }
346
347        let hashes = crate::phf::hashing::hash(buf, key, &self.key.to_ne())?;
348
349        let displacements = |index| match self.displacements.get(index) {
350            Some(entry) => Ok(Some(buf.load(entry)?)),
351            None => Ok(None),
352        };
353
354        let index = crate::phf::hashing::get_custom_index(
355            &hashes,
356            displacements,
357            self.displacements.len(),
358            self.entries.len(),
359        )?;
360
361        let Some(e) = self.entries.get(index) else {
362            return Ok(None);
363        };
364
365        let e = buf.load(e)?;
366
367        if key.visit(buf, |b| e.key.visit(buf, |a| a.borrow() == b))?? {
368            Ok(Some((&e.key, &e.value)))
369        } else {
370            Ok(None)
371        }
372    }
373}
374
375impl<K, V, E, O> Clone for MapRef<K, V, E, O>
376where
377    K: ZeroCopy,
378    V: ZeroCopy,
379    E: ByteOrder,
380    O: Size,
381{
382    fn clone(&self) -> Self {
383        *self
384    }
385}
386
387impl<K, V, E, O> Copy for MapRef<K, V, E, O>
388where
389    K: ZeroCopy,
390    V: ZeroCopy,
391    E: ByteOrder,
392    O: Size,
393{
394}