Skip to main content

prefix_trie/joint/map/
entry.rs

1//! Code for inserting elements and the entry pattern.
2
3use crate::joint::JointPrefix;
4
5/// A mutable view into a single entry in a map, which may either be vacant or occupied.
6pub enum Entry<'a, P: JointPrefix, T> {
7    /// The entry is not present in the tree.
8    Vacant(VacantEntry<'a, P, T>),
9    /// The entry is already present in the tree.
10    Occupied(OccupiedEntry<'a, P, T>),
11}
12
13/// A mutable view into a missing entry. The information within this structure describes a path
14/// towards that missing node, and how to insert it.
15pub enum VacantEntry<'a, P: JointPrefix, T> {
16    /// Vacant entry for the first prefix variant
17    P1(crate::map::VacantEntry<'a, P::P1, T>),
18    /// Vacant entry for the second prefix variant
19    P2(crate::map::VacantEntry<'a, P::P2, T>),
20}
21
22/// A mutable view into an occupied entry. An occupied entry represents a node that is already
23/// present on the tree.
24pub enum OccupiedEntry<'a, P: JointPrefix, T> {
25    /// Occupied entry for the first prefix variant
26    P1(crate::map::OccupiedEntry<'a, P::P1, T>),
27    /// Occupied entry for the second prefix variant
28    P2(crate::map::OccupiedEntry<'a, P::P2, T>),
29}
30
31impl<'a, P: JointPrefix, T> Entry<'a, P, T> {
32    /// Get the value if it exists
33    pub fn get(&self) -> Option<&T> {
34        match self {
35            Entry::Vacant(_) => None,
36            Entry::Occupied(e) => Some(e.get()),
37        }
38    }
39
40    /// Get the value if it exists
41    pub fn get_mut(&mut self) -> Option<&mut T> {
42        match self {
43            Entry::Vacant(_) => None,
44            Entry::Occupied(e) => Some(e.get_mut()),
45        }
46    }
47
48    /// get the key of the current entry
49    pub fn key(&self) -> P {
50        match self {
51            Entry::Vacant(e) => e.key(),
52            Entry::Occupied(e) => e.key(),
53        }
54    }
55
56    /// Replace the current entry, and return the entry that was stored before.
57    ///
58    /// Prefixes are not stored verbatim. They are reconstructed from the trie position, so host
59    /// bits masked out by the prefix length are not preserved.
60    ///
61    /// ```
62    /// # use prefix_trie::joint::*;
63    /// # #[cfg(feature = "ipnet")]
64    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
65    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
66    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).insert(1), None);
67    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).insert(2), Some(1));
68    /// # Ok(())
69    /// # }
70    /// # #[cfg(not(feature = "ipnet"))]
71    /// # fn main() {}
72    /// ```
73    ///
74    /// Host bits from the `entry` argument are not preserved:
75    ///
76    /// ```
77    /// # use prefix_trie::joint::*;
78    /// # #[cfg(feature = "ipnet")]
79    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
80    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
81    /// pm.insert("192.168.1.1/24".parse()?, 1);
82    /// pm.entry("192.168.1.2/24".parse()?).insert(2);
83    /// assert_eq!(
84    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
85    ///     Some(("192.168.1.0/24".parse()?, &2))
86    /// );
87    /// # Ok(())
88    /// # }
89    /// # #[cfg(not(feature = "ipnet"))]
90    /// # fn main() {}
91    /// ```
92    #[inline(always)]
93    pub fn insert(self, v: T) -> Option<T> {
94        match self {
95            Entry::Vacant(e) => {
96                e.insert(v);
97                None
98            }
99            Entry::Occupied(e) => Some(e.insert(v)),
100        }
101    }
102
103    /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable
104    /// reference to the value in the entry.
105    ///
106    /// ```
107    /// # use prefix_trie::joint::*;
108    /// # #[cfg(feature = "ipnet")]
109    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
110    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
111    /// pm.insert("192.168.1.0/24".parse()?, 1);
112    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).or_insert(10), &1);
113    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).or_insert(20), &20);
114    /// # Ok(())
115    /// # }
116    /// # #[cfg(not(feature = "ipnet"))]
117    /// # fn main() {}
118    /// ```
119    ///
120    /// Host bits from an existing matching prefix are not preserved.
121    ///
122    /// ```
123    /// # use prefix_trie::joint::*;
124    /// # #[cfg(feature = "ipnet")]
125    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
126    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
127    /// pm.insert("192.168.1.1/24".parse()?, 1);
128    /// pm.entry("192.168.1.2/24".parse()?).or_insert(2);
129    /// assert_eq!(
130    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
131    ///     Some(("192.168.1.0/24".parse()?, &1))
132    /// );
133    /// # Ok(())
134    /// # }
135    /// # #[cfg(not(feature = "ipnet"))]
136    /// # fn main() {}
137    /// ```
138    #[inline(always)]
139    pub fn or_insert(self, default: T) -> &'a mut T {
140        match self {
141            Entry::Vacant(e) => e.insert(default),
142            Entry::Occupied(e) => match e {
143                OccupiedEntry::P1(e) => e.into_mut(),
144                OccupiedEntry::P2(e) => e.into_mut(),
145            },
146        }
147    }
148
149    /// Ensures a value is in the entry by inserting the result of the default function if empty,
150    /// and returns a mutable reference to the value in the entry.
151    ///
152    /// ```
153    /// # use prefix_trie::joint::*;
154    /// # #[cfg(feature = "ipnet")]
155    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
156    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
157    /// pm.insert("192.168.1.0/24".parse()?, 1);
158    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).or_insert_with(|| 10), &1);
159    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).or_insert_with(|| 20), &20);
160    /// # Ok(())
161    /// # }
162    /// # #[cfg(not(feature = "ipnet"))]
163    /// # fn main() {}
164    /// ```
165    ///
166    /// Host bits from an existing matching prefix are not preserved.
167    ///
168    /// ```
169    /// # use prefix_trie::joint::*;
170    /// # #[cfg(feature = "ipnet")]
171    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
172    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
173    /// pm.insert("192.168.1.1/24".parse()?, 1);
174    /// pm.entry("192.168.1.2/24".parse()?).or_insert_with(|| 2);
175    /// assert_eq!(
176    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
177    ///     Some(("192.168.1.0/24".parse()?, &1))
178    /// );
179    /// # Ok(())
180    /// # }
181    /// # #[cfg(not(feature = "ipnet"))]
182    /// # fn main() {}
183    /// ```
184    #[inline(always)]
185    pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T {
186        match self {
187            Entry::Vacant(e) => e.insert(default()),
188            Entry::Occupied(e) => match e {
189                OccupiedEntry::P1(e) => e.into_mut(),
190                OccupiedEntry::P2(e) => e.into_mut(),
191            },
192        }
193    }
194
195    /// Provides in-place mutable access to an occupied entry before any potential inserts into the
196    /// map.
197    ///
198    /// ```
199    /// # use prefix_trie::joint::*;
200    /// # #[cfg(feature = "ipnet")]
201    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
202    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
203    /// pm.insert("192.168.1.0/24".parse()?, 1);
204    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).and_modify(|x| *x += 1).get(), Some(&2));
205    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).and_modify(|x| *x += 1).get(), None);
206    /// # Ok(())
207    /// # }
208    /// # #[cfg(not(feature = "ipnet"))]
209    /// # fn main() {}
210    /// ```
211    ///
212    /// Host bits from an existing matching prefix are not preserved.
213    ///
214    /// ```
215    /// # use prefix_trie::joint::*;
216    /// # #[cfg(feature = "ipnet")]
217    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
218    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
219    /// pm.insert("192.168.1.1/24".parse()?, 1);
220    /// pm.entry("192.168.1.2/24".parse()?).and_modify(|x| *x += 1);
221    /// assert_eq!(
222    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
223    ///     Some(("192.168.1.0/24".parse()?, &2))
224    /// );
225    /// # Ok(())
226    /// # }
227    /// # #[cfg(not(feature = "ipnet"))]
228    /// # fn main() {}
229    /// ```
230    #[inline(always)]
231    pub fn and_modify<F: FnOnce(&mut T)>(self, f: F) -> Self {
232        match self {
233            Entry::Vacant(e) => Entry::Vacant(e),
234            Entry::Occupied(e) => match e {
235                OccupiedEntry::P1(mut e) => {
236                    f(e.get_mut());
237                    Entry::Occupied(OccupiedEntry::P1(e))
238                }
239                OccupiedEntry::P2(mut e) => {
240                    f(e.get_mut());
241                    Entry::Occupied(OccupiedEntry::P2(e))
242                }
243            },
244        }
245    }
246}
247
248impl<'a, P, T> Entry<'a, P, T>
249where
250    P: JointPrefix,
251    T: Default,
252{
253    /// Ensures a value is in the entry by inserting the default value if empty, and returns a
254    /// mutable reference to the value in the entry.
255    ///
256    /// ```
257    /// # use prefix_trie::joint::*;
258    /// # #[cfg(feature = "ipnet")]
259    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
260    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
261    /// pm.insert("192.168.1.0/24".parse()?, 1);
262    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).or_default(), &1);
263    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).or_default(), &0);
264    /// # Ok(())
265    /// # }
266    /// # #[cfg(not(feature = "ipnet"))]
267    /// # fn main() {}
268    /// ```
269    ///
270    /// Host bits from an existing matching prefix are not preserved.
271    ///
272    /// ```
273    /// # use prefix_trie::joint::*;
274    /// # #[cfg(feature = "ipnet")]
275    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
276    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
277    /// pm.insert("192.168.1.1/24".parse()?, 1);
278    /// pm.entry("192.168.1.2/24".parse()?).or_default();
279    /// assert_eq!(
280    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
281    ///     Some(("192.168.1.0/24".parse()?, &1))
282    /// );
283    /// # Ok(())
284    /// # }
285    /// # #[cfg(not(feature = "ipnet"))]
286    /// # fn main() {}
287    /// ```
288    #[allow(clippy::unwrap_or_default)]
289    #[inline(always)]
290    pub fn or_default(self) -> &'a mut T {
291        self.or_insert_with(Default::default)
292    }
293}
294
295impl<P: JointPrefix, T> OccupiedEntry<'_, P, T> {
296    /// Gets a reference to the key in the entry. This is the key that is currently stored, and not
297    /// the key that was used in the insert.
298    pub fn key(&self) -> P {
299        match self {
300            OccupiedEntry::P1(e) => P::from_p1(e.key()),
301            OccupiedEntry::P2(e) => P::from_p2(e.key()),
302        }
303    }
304
305    /// Gets a reference to the value in the entry.
306    pub fn get(&self) -> &T {
307        match self {
308            OccupiedEntry::P1(e) => e.get(),
309            OccupiedEntry::P2(e) => e.get(),
310        }
311    }
312
313    /// Gets a mutable reference to the value in the entry.
314    ///
315    /// Prefixes are not stored verbatim. They are reconstructed from the trie position, so host
316    /// bits masked out by the prefix length are not preserved.
317    ///
318    /// ```
319    /// # use prefix_trie::joint::*;
320    /// use prefix_trie::joint::map::Entry;
321    /// # #[cfg(feature = "ipnet")]
322    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
323    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
324    /// pm.insert("192.168.1.1/24".parse()?, 1);
325    /// if let Entry::Occupied(mut e) = pm.entry("192.168.1.0/24".parse()?) {
326    ///     *e.get_mut() += 1;
327    /// }
328    /// assert_eq!(
329    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
330    ///     Some(("192.168.1.0/24".parse()?, &2))
331    /// );
332    /// # Ok(())
333    /// # }
334    /// # #[cfg(not(feature = "ipnet"))]
335    /// # fn main() {}
336    /// ```
337    pub fn get_mut(&mut self) -> &mut T {
338        match self {
339            OccupiedEntry::P1(e) => e.get_mut(),
340            OccupiedEntry::P2(e) => e.get_mut(),
341        }
342    }
343
344    /// Insert a new value into the entry, returning the old value.
345    ///
346    /// ```
347    /// # use prefix_trie::joint::*;
348    /// use prefix_trie::joint::map::Entry;
349    /// # #[cfg(feature = "ipnet")]
350    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
351    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
352    /// pm.insert("192.168.1.1/24".parse()?, 1);
353    /// if let Entry::Occupied(mut e) = pm.entry("192.168.1.0/24".parse()?) {
354    ///     e.insert(2);
355    /// }
356    /// assert_eq!(
357    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
358    ///     Some(("192.168.1.0/24".parse()?, &2))
359    /// );
360    /// # Ok(())
361    /// # }
362    /// # #[cfg(not(feature = "ipnet"))]
363    /// # fn main() {}
364    /// ```
365    pub fn insert(self, value: T) -> T {
366        match self {
367            OccupiedEntry::P1(e) => e.insert(value),
368            OccupiedEntry::P2(e) => e.insert(value),
369        }
370    }
371
372    /// Remove the current value and return it. Empty trie nodes may be left in place (the same
373    /// effect as `JointPrefixMap::remove_keep_tree`).
374    pub fn remove(self) -> T {
375        match self {
376            OccupiedEntry::P1(e) => e.remove(),
377            OccupiedEntry::P2(e) => e.remove(),
378        }
379    }
380}
381
382impl<'a, P: JointPrefix, T> VacantEntry<'a, P, T> {
383    /// Gets a reference to the key in the entry.
384    pub fn key(&self) -> P {
385        match self {
386            VacantEntry::P1(e) => P::from_p1(e.key()),
387            VacantEntry::P2(e) => P::from_p2(e.key()),
388        }
389    }
390
391    /// Get a mutable reference to the value. If the value is yet empty, set it to the given default
392    /// value.
393    pub fn insert(self, default: T) -> &'a mut T {
394        match self {
395            VacantEntry::P1(e) => e.insert(default),
396            VacantEntry::P2(e) => e.insert(default),
397        }
398    }
399
400    /// Get a mutable reference to the value. If the value is yet empty, set it to the return value
401    /// from the given function.
402    pub fn insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T {
403        match self {
404            VacantEntry::P1(e) => e.insert_with(default),
405            VacantEntry::P2(e) => e.insert_with(default),
406        }
407    }
408}
409
410impl<'a, P, T> VacantEntry<'a, P, T>
411where
412    P: JointPrefix,
413    T: Default,
414{
415    /// Get a mutable reference to the value. If the value is yet empty, set it to the default value
416    /// using `Default::default()`.
417    pub fn default(self) -> &'a mut T {
418        match self {
419            VacantEntry::P1(e) => e.default(),
420            VacantEntry::P2(e) => e.default(),
421        }
422    }
423}