musli_zerocopy/swiss/set.rs
1//! A set which implements a hash-set like interface, where values can be looked
2//! up by keys.
3//!
4//! This set are implemented using a perfect hash functions, and are inserted
5//! into a buffering using [`swiss::store_set`].
6//!
7//! There's two types provided by this module:
8//! * [`Set<T>`] which is a *bound* reference to a set, providing a convenient
9//! set-like access.
10//! * [`SetRef<T>`] which is the *pointer* of the set. This is what you store in
11//! [`ZeroCopy`] types and is what is returned by [`swiss::store_set`].
12//!
13//! [`swiss::store_set`]: crate::swiss::store_set
14
15use core::borrow::Borrow;
16use core::hash::{Hash, Hasher};
17
18use crate::ZeroCopy;
19use crate::buf::{Bindable, Buf, Visit};
20use crate::endian::{ByteOrder, Native};
21use crate::error::Error;
22use crate::pointer::{DefaultSize, Size};
23use crate::sip::SipHasher13;
24use crate::swiss::map::{RawTable, RawTableRef};
25
26/// A set bound to a [`Buf`] through [`Buf::bind`] for convenience.
27///
28/// ## Examples
29///
30/// ```
31/// use musli_zerocopy::OwnedBuf;
32/// use musli_zerocopy::swiss;
33///
34/// let mut buf = OwnedBuf::new();
35///
36/// let set = swiss::store_set(&mut buf, [1, 2])?;
37/// let set = buf.bind(set)?;
38///
39/// assert!(set.contains(&1)?);
40/// assert!(set.contains(&2)?);
41/// assert!(!set.contains(&3)?);
42/// # Ok::<_, musli_zerocopy::Error>(())
43/// ```
44pub struct Set<'a, T> {
45 key: u64,
46 table: RawTable<'a, T>,
47 buf: &'a Buf,
48}
49
50impl<T> Set<'_, T>
51where
52 T: ZeroCopy,
53{
54 /// Test if the set contains the given `value`.
55 ///
56 /// ## Examples
57 ///
58 /// ```
59 /// use musli_zerocopy::OwnedBuf;
60 /// use musli_zerocopy::swiss;
61 ///
62 /// let mut buf = OwnedBuf::new();
63 ///
64 /// let set = swiss::store_set(&mut buf, [1, 2])?;
65 /// let set = buf.bind(set)?;
66 ///
67 /// assert!(set.contains(&1)?);
68 /// assert!(set.contains(&2)?);
69 /// assert!(!set.contains(&3)?);
70 /// # Ok::<_, musli_zerocopy::Error>(())
71 /// ```
72 pub fn contains<Q>(&self, value: &Q) -> Result<bool, Error>
73 where
74 Q: ?Sized + Visit,
75 Q::Target: Eq + Hash,
76 T: Visit,
77 T::Target: Borrow<Q::Target>,
78 {
79 let hash = value.visit(self.buf, |k| self.hash(k))?;
80
81 let entry = self.table.find(hash, |e| {
82 value.visit(self.buf, |b| e.visit(self.buf, |a| a.borrow() == b))?
83 })?;
84
85 Ok(entry.is_some())
86 }
87
88 fn hash<H>(&self, value: &H) -> u64
89 where
90 H: ?Sized + Hash,
91 {
92 let mut hasher = SipHasher13::new_with_keys(0, self.key);
93 value.hash(&mut hasher);
94 hasher.finish()
95 }
96}
97
98/// Bind a [`SetRef`] into a [`Set`].
99impl<T, E, O> Bindable for SetRef<T, E, O>
100where
101 T: ZeroCopy,
102 E: ByteOrder,
103 O: Size,
104{
105 type Bound<'a>
106 = Set<'a, T>
107 where
108 Self: 'a;
109
110 #[inline]
111 fn bind(self, buf: &Buf) -> Result<Self::Bound<'_>, Error> {
112 Ok(Set {
113 key: self.key,
114 table: self.table.bind(buf)?,
115 buf,
116 })
117 }
118}
119
120/// A stored reference to a set.
121///
122/// Note that operating over the methods provided in [`SetRef`] does not demand
123/// that the entire contents of the set is validated as would be the case when
124/// [`bind()`] is used and might result in better performance if the data is
125/// infrequently accessed.
126///
127/// Constructed through [`swiss::store_set`].
128///
129/// [`swiss::store_set`]: crate::swiss::store_set
130/// [`bind()`]: crate::buf::Buf::bind
131///
132/// ## Examples
133///
134/// ```
135/// use musli_zerocopy::OwnedBuf;
136/// use musli_zerocopy::swiss;
137///
138/// let mut buf = OwnedBuf::new();
139///
140/// let set = swiss::store_set(&mut buf, [1, 2])?;
141///
142/// assert!(set.contains(&buf, &1)?);
143/// assert!(!set.contains(&buf, &3)?);
144/// # Ok::<_, musli_zerocopy::Error>(())
145/// ```
146#[derive(Debug, ZeroCopy)]
147#[repr(C)]
148#[zero_copy(crate)]
149pub struct SetRef<T, E = Native, O = DefaultSize>
150where
151 T: ZeroCopy,
152 E: ByteOrder,
153 O: Size,
154{
155 key: u64,
156 table: RawTableRef<T, E, O>,
157}
158
159impl<T, E, O> SetRef<T, E, O>
160where
161 T: ZeroCopy,
162 E: ByteOrder,
163 O: Size,
164{
165 #[cfg(feature = "alloc")]
166 pub(crate) fn new(key: u64, table: RawTableRef<T, E, O>) -> Self {
167 Self { key, table }
168 }
169
170 /// Test if the set contains the given `key`.
171 ///
172 /// ## Examples
173 ///
174 /// ```
175 /// use musli_zerocopy::OwnedBuf;
176 /// use musli_zerocopy::swiss;
177 ///
178 /// let mut buf = OwnedBuf::new();
179 ///
180 /// let set = swiss::store_set(&mut buf, [1, 2])?;
181 ///
182 /// assert!(set.contains(&buf, &1)?);
183 /// assert!(set.contains(&buf, &2)?);
184 /// assert!(!set.contains(&buf, &3)?);
185 /// # Ok::<_, musli_zerocopy::Error>(())
186 /// ```
187 pub fn contains<Q>(&self, buf: &Buf, key: &Q) -> Result<bool, Error>
188 where
189 Q: ?Sized + Visit,
190 Q::Target: Eq + Hash,
191 T: Visit,
192 T::Target: Borrow<Q::Target>,
193 {
194 let hash = key.visit(buf, |key| self.hash(key))?;
195
196 let entry = self.table.find(buf, hash, |e| {
197 key.visit(buf, |b| e.visit(buf, |a| a.borrow() == b))?
198 })?;
199
200 Ok(entry.is_some())
201 }
202
203 fn hash<H>(&self, value: &H) -> u64
204 where
205 H: ?Sized + Hash,
206 {
207 let mut hasher = SipHasher13::new_with_keys(0, self.key);
208 value.hash(&mut hasher);
209 hasher.finish()
210 }
211}