prefix_trie/map/
entry.rs

1//! Code for inserting elements and the entry pattern.
2
3use super::*;
4
5/// A mutable view into a single entry in a map, which may either be vacant or occupied.
6pub enum Entry<'a, P, 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 struct VacantEntry<'a, P, T> {
16    pub(super) map: &'a mut PrefixMap<P, T>,
17    pub(super) prefix: P,
18    pub(super) idx: usize,
19    pub(super) direction: DirectionForInsert<P>,
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 struct OccupiedEntry<'a, P, T> {
25    pub(super) node: &'a mut Node<P, T>,
26    pub(super) prefix: P, // needed to replace the prefix on the thing if we perform insert.
27}
28
29impl<P, T> Entry<'_, P, T> {
30    /// Get the value if it exists
31    ///
32    /// ```
33    /// # use prefix_trie::*;
34    /// # #[cfg(feature = "ipnet")]
35    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
36    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
37    /// pm.insert("192.168.1.0/24".parse()?, 1);
38    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).get(), Some(&1));
39    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).get(), None);
40    /// # Ok(())
41    /// # }
42    /// # #[cfg(not(feature = "ipnet"))]
43    /// # fn main() {}
44    /// ```
45    pub fn get(&self) -> Option<&T> {
46        match self {
47            Entry::Vacant(_) => None,
48            Entry::Occupied(e) => e.node.value.as_ref(),
49        }
50    }
51
52    /// Get the value if it exists
53    ///
54    /// ```
55    /// # use prefix_trie::*;
56    /// # #[cfg(feature = "ipnet")]
57    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
58    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
59    /// pm.insert("192.168.1.0/24".parse()?, 1);
60    /// pm.entry("192.168.1.0/24".parse()?).get_mut().map(|x| *x += 1);
61    /// pm.entry("192.168.2.0/24".parse()?).get_mut().map(|x| *x += 1);
62    /// assert_eq!(pm.get(&"192.168.1.0/24".parse()?), Some(&2));
63    /// assert_eq!(pm.get(&"192.168.2.0/24".parse()?), None);
64    /// # Ok(())
65    /// # }
66    /// # #[cfg(not(feature = "ipnet"))]
67    /// # fn main() {}
68    /// ```
69    pub fn get_mut(&mut self) -> Option<&mut T> {
70        match self {
71            Entry::Vacant(_) => None,
72            Entry::Occupied(e) => e.node.value.as_mut(),
73        }
74    }
75
76    /// get the key of the current entry
77    ///
78    /// ```
79    /// # use prefix_trie::*;
80    /// # #[cfg(feature = "ipnet")]
81    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
82    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
83    /// pm.insert("192.168.1.0/24".parse()?, 1);
84    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).key(), &"192.168.1.0/24".parse()?);
85    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).key(), &"192.168.2.0/24".parse()?);
86    /// # Ok(())
87    /// # }
88    /// # #[cfg(not(feature = "ipnet"))]
89    /// # fn main() {}
90    /// ```
91    pub fn key(&self) -> &P {
92        match self {
93            Entry::Vacant(e) => &e.prefix,
94            Entry::Occupied(e) => &e.node.prefix,
95        }
96    }
97}
98
99impl<'a, P, T> Entry<'a, P, T>
100where
101    P: Prefix,
102{
103    /// Replace the current entry, and return the entry that was stored before. This will also
104    /// replace the key with the one provided to the `entry` function.
105    ///
106    /// ```
107    /// # use prefix_trie::*;
108    /// # #[cfg(feature = "ipnet")]
109    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
110    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
111    /// pm.insert("192.168.1.0/24".parse()?, 1);
112    ///
113    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).insert(10), Some(1));
114    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).insert(20), None);
115    ///
116    /// assert_eq!(pm.get(&"192.168.1.0/24".parse()?), Some(&10));
117    /// assert_eq!(pm.get(&"192.168.2.0/24".parse()?), Some(&20));
118    /// # Ok(())
119    /// # }
120    /// # #[cfg(not(feature = "ipnet"))]
121    /// # fn main() {}
122    /// ```
123    #[inline(always)]
124    pub fn insert(self, v: T) -> Option<T> {
125        match self {
126            Entry::Vacant(e) => {
127                e._insert(v);
128                None
129            }
130            Entry::Occupied(e) => Some(e.insert(v)),
131        }
132    }
133
134    /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable
135    /// reference to the value in the entry.
136    ///
137    /// ```
138    /// # use prefix_trie::*;
139    /// # #[cfg(feature = "ipnet")]
140    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
141    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
142    /// pm.insert("192.168.1.0/24".parse()?, 1);
143    ///
144    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).or_insert(10), &1);
145    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).or_insert(20), &20);
146    ///
147    /// assert_eq!(pm.get(&"192.168.1.0/24".parse()?), Some(&1));
148    /// assert_eq!(pm.get(&"192.168.2.0/24".parse()?), Some(&20));
149    /// # Ok(())
150    /// # }
151    /// # #[cfg(not(feature = "ipnet"))]
152    /// # fn main() {}
153    /// ```
154    #[inline(always)]
155    pub fn or_insert(self, default: T) -> &'a mut T {
156        match self {
157            Entry::Vacant(e) => e._insert(default).value.as_mut().unwrap(),
158            Entry::Occupied(e) => e.node.value.get_or_insert(default),
159        }
160    }
161
162    /// Ensures a value is in the entry by inserting the result of the default function if empty,
163    /// and returns a mutable reference to the value in the entry.
164    ///
165    /// ```
166    /// # use prefix_trie::*;
167    /// # #[cfg(feature = "ipnet")]
168    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
169    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
170    /// pm.insert("192.168.1.0/24".parse()?, 1);
171    ///
172    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).or_insert_with(|| 10), &1);
173    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).or_insert_with(|| 20), &20);
174    ///
175    /// assert_eq!(pm.get(&"192.168.1.0/24".parse()?), Some(&1));
176    /// assert_eq!(pm.get(&"192.168.2.0/24".parse()?), Some(&20));
177    /// # Ok(())
178    /// # }
179    /// # #[cfg(not(feature = "ipnet"))]
180    /// # fn main() {}
181    /// ```
182    #[inline(always)]
183    pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T {
184        match self {
185            Entry::Vacant(e) => e._insert(default()).value.as_mut().unwrap(),
186            Entry::Occupied(e) => e.node.value.get_or_insert_with(default),
187        }
188    }
189
190    /// Provides in-place mutable access to an occupied entry before any potential inserts into the
191    /// map.
192    ///
193    /// ```
194    /// # use prefix_trie::*;
195    /// # #[cfg(feature = "ipnet")]
196    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
197    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
198    /// pm.insert("192.168.1.0/24".parse()?, 1);
199    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).and_modify(|x| *x += 1).get(), Some(&2));
200    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).and_modify(|x| *x += 1).get(), None);
201    /// # Ok(())
202    /// # }
203    /// # #[cfg(not(feature = "ipnet"))]
204    /// # fn main() {}
205    /// ```
206    #[inline(always)]
207    pub fn and_modify<F: FnOnce(&mut T)>(self, f: F) -> Self {
208        match self {
209            Entry::Vacant(e) => Entry::Vacant(e),
210            Entry::Occupied(e) => {
211                e.node.value.as_mut().map(f);
212                Entry::Occupied(e)
213            }
214        }
215    }
216}
217
218impl<'a, P, T> Entry<'a, P, T>
219where
220    P: Prefix,
221    T: Default,
222{
223    /// Ensures a value is in the entry by inserting the default value if empty, and returns a
224    /// mutable reference to the value in the entry.
225    ///
226    /// ```
227    /// # use prefix_trie::*;
228    /// # #[cfg(feature = "ipnet")]
229    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
230    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
231    /// pm.insert("192.168.1.0/24".parse()?, 1);
232    ///
233    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).or_default(), &1);
234    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).or_default(), &0);
235    ///
236    /// assert_eq!(pm.get(&"192.168.1.0/24".parse()?), Some(&1));
237    /// assert_eq!(pm.get(&"192.168.2.0/24".parse()?), Some(&0));
238    /// # Ok(())
239    /// # }
240    /// # #[cfg(not(feature = "ipnet"))]
241    /// # fn main() {}
242    /// ```
243    #[allow(clippy::unwrap_or_default)]
244    #[inline(always)]
245    pub fn or_default(self) -> &'a mut T {
246        self.or_insert_with(Default::default)
247    }
248}
249
250impl<'a, P, T> VacantEntry<'a, P, T>
251where
252    P: Prefix,
253{
254    fn _insert(self, v: T) -> &'a mut Node<P, T> {
255        match self.direction {
256            DirectionForInsert::Reached => {
257                // increment the count, as node.value will be `None`. We do it here as we borrow
258                // `map` mutably in the next line.
259                self.map.count += 1;
260                let node = &mut self.map.table[self.idx];
261                node.prefix = self.prefix;
262                debug_assert!(node.value.is_none());
263                node.value = Some(v);
264                node
265            }
266            DirectionForInsert::NewLeaf { right } => {
267                let new = self.map.new_node(self.prefix, Some(v));
268                self.map.table.set_child(self.idx, new, right);
269                &mut self.map.table[new]
270            }
271            DirectionForInsert::NewChild { right, child_right } => {
272                let new = self.map.new_node(self.prefix, Some(v));
273                let child = self.map.table.set_child(self.idx, new, right).unwrap();
274                self.map.table.set_child(new, child, child_right);
275                &mut self.map.table[new]
276            }
277            DirectionForInsert::NewBranch {
278                branch_prefix,
279                right,
280                prefix_right,
281            } => {
282                let branch = self.map.new_node(branch_prefix, None);
283                let new = self.map.new_node(self.prefix, Some(v));
284                let child = self.map.table.set_child(self.idx, branch, right).unwrap();
285                self.map.table.set_child(branch, new, prefix_right);
286                self.map.table.set_child(branch, child, !prefix_right);
287                &mut self.map.table[new]
288            }
289            DirectionForInsert::Enter { .. } => unreachable!(),
290        }
291    }
292}
293
294impl<P, T> OccupiedEntry<'_, P, T> {
295    /// Gets a reference to the key in the entry. This is the key that is currently stored, and not
296    /// the key that was used in the insert.
297    ///
298    /// ```
299    /// # use prefix_trie::*;
300    /// use prefix_trie::map::Entry;
301    /// # #[cfg(feature = "ipnet")]
302    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
303    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
304    /// pm.insert("192.168.1.0/24".parse()?, 1);
305    /// match pm.entry("192.168.1.1/24".parse()?) {
306    ///     Entry::Occupied(e) => assert_eq!(e.key(), &"192.168.1.0/24".parse()?),
307    ///     Entry::Vacant(_) => unreachable!(),
308    /// }
309    /// # Ok(())
310    /// # }
311    /// # #[cfg(not(feature = "ipnet"))]
312    /// # fn main() {}
313    /// ```
314    pub fn key(&self) -> &P {
315        &self.node.prefix
316    }
317
318    /// Gets a reference to the value in the entry.
319    ///
320    /// ```
321    /// # use prefix_trie::*;
322    /// use prefix_trie::map::Entry;
323    /// # #[cfg(feature = "ipnet")]
324    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
325    ///
326    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
327    /// pm.insert("192.168.1.0/24".parse()?, 1);
328    /// match pm.entry("192.168.1.0/24".parse()?) {
329    ///     Entry::Occupied(e) => assert_eq!(e.get(), &1),
330    ///     Entry::Vacant(_) => unreachable!(),
331    /// }
332    /// # Ok(())
333    /// # }
334    /// # #[cfg(not(feature = "ipnet"))]
335    /// # fn main() {}
336    /// ```
337    pub fn get(&self) -> &T {
338        self.node.value.as_ref().unwrap()
339    }
340
341    /// Gets a mutable reference to the value in the entry.
342    ///
343    /// This call will not modify the prefix stored in the tree. In case the prefix used to create
344    /// the entry is different from the stored one (has additional information in the host part),
345    /// and you wish that prefix to be overwritten, use `insert`.
346    ///
347    /// ```
348    /// # use prefix_trie::*;
349    /// use prefix_trie::map::Entry;
350    /// # #[cfg(feature = "ipnet")]
351    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
352    ///
353    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
354    /// pm.insert("192.168.1.0/24".parse()?, 1);
355    /// match pm.entry("192.168.1.0/24".parse()?) {
356    ///     Entry::Occupied(mut e) => *e.get_mut() += 1,
357    ///     Entry::Vacant(_) => unreachable!(),
358    /// }
359    /// assert_eq!(pm.get(&"192.168.1.0/24".parse()?), Some(&2));
360    /// # Ok(())
361    /// # }
362    /// # #[cfg(not(feature = "ipnet"))]
363    /// # fn main() {}
364    /// ```
365    pub fn get_mut(&mut self) -> &mut T {
366        self.node.value.as_mut().unwrap()
367    }
368
369    /// Insert a new value into the entry, returning the old value. This operation will also replace
370    /// the prefix with the provided one.
371    ///
372    /// ```
373    /// # use prefix_trie::*;
374    /// use prefix_trie::map::Entry;
375    /// # #[cfg(feature = "ipnet")]
376    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
377    ///
378    /// let mut pm: PrefixMap<ipnet::Ipv4Net, _> = PrefixMap::new();
379    /// pm.insert("192.168.1.0/24".parse()?, 1);
380    /// match pm.entry("192.168.1.0/24".parse()?) {
381    ///     Entry::Occupied(mut e) => assert_eq!(e.insert(10), 1),
382    ///     Entry::Vacant(_) => unreachable!(),
383    /// }
384    /// assert_eq!(pm.get(&"192.168.1.0/24".parse()?), Some(&10));
385    /// # Ok(())
386    /// # }
387    /// # #[cfg(not(feature = "ipnet"))]
388    /// # fn main() {}
389    /// ```
390    pub fn insert(self, value: T) -> T {
391        self.node.prefix = self.prefix;
392        self.node.value.replace(value).unwrap()
393    }
394
395    /// Remove the current value and return it. The tree will not be modified (the same effect as
396    /// `PrefixMap::remove_keep_tree`).
397    ///
398    /// ```
399    /// # use prefix_trie::*;
400    /// use prefix_trie::map::Entry;
401    /// # #[cfg(feature = "ipnet")]
402    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
403    ///
404    /// let mut pm: PrefixMap<ipnet::Ipv4Net, i32> = PrefixMap::new();
405    /// pm.insert("192.168.1.0/24".parse()?, 1);
406    /// match pm.entry("192.168.1.0/24".parse()?) {
407    ///     Entry::Occupied(mut e) => assert_eq!(e.remove(), 1),
408    ///     Entry::Vacant(_) => unreachable!(),
409    /// }
410    /// assert_eq!(pm.get(&"192.168.1.0/24".parse()?), None);
411    /// # Ok(())
412    /// # }
413    /// # #[cfg(not(feature = "ipnet"))]
414    /// # fn main() {}
415    /// ```
416    pub fn remove(&mut self) -> T {
417        self.node.value.take().unwrap()
418    }
419}
420
421impl<P, T> VacantEntry<'_, P, T> {
422    /// Gets a reference to the key in the entry.
423    ///
424    /// ```
425    /// # use prefix_trie::*;
426    /// use prefix_trie::map::Entry;
427    /// # #[cfg(feature = "ipnet")]
428    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
429    /// let mut pm: PrefixMap<ipnet::Ipv4Net, i32> = PrefixMap::new();
430    /// match pm.entry("192.168.1.0/24".parse()?) {
431    ///     Entry::Vacant(e) => assert_eq!(e.key(), &"192.168.1.0/24".parse()?),
432    ///     Entry::Occupied(_) => unreachable!(),
433    /// }
434    /// # Ok(())
435    /// # }
436    /// # #[cfg(not(feature = "ipnet"))]
437    /// # fn main() {}
438    /// ```
439    pub fn key(&self) -> &P {
440        &self.prefix
441    }
442}
443
444impl<'a, P, T> VacantEntry<'a, P, T>
445where
446    P: Prefix,
447{
448    /// Get a mutable reference to the value. If the value is yet empty, set it to the given default
449    /// value.
450    ///
451    /// ```
452    /// # use prefix_trie::*;
453    /// use prefix_trie::map::Entry;
454    /// # #[cfg(feature = "ipnet")]
455    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
456    /// let mut pm: PrefixMap<ipnet::Ipv4Net, i32> = PrefixMap::new();
457    /// match pm.entry("192.168.1.0/24".parse()?) {
458    ///     Entry::Vacant(mut e) => assert_eq!(e.insert(10), &10),
459    ///     Entry::Occupied(_) => unreachable!(),
460    /// }
461    /// assert_eq!(pm.get(&"192.168.1.0/24".parse()?), Some(&10));
462    /// # Ok(())
463    /// # }
464    /// # #[cfg(not(feature = "ipnet"))]
465    /// # fn main() {}
466    /// ```
467    pub fn insert(self, default: T) -> &'a mut T {
468        let node = self._insert(default);
469        node.value.as_mut().unwrap()
470    }
471
472    /// Get a mutable reference to the value. If the value is yet empty, set it to the return value
473    /// from the given function.
474    ///
475    /// ```
476    /// # use prefix_trie::*;
477    /// use prefix_trie::map::Entry;
478    /// # #[cfg(feature = "ipnet")]
479    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
480    /// let mut pm: PrefixMap<ipnet::Ipv4Net, i32> = PrefixMap::new();
481    /// match pm.entry("192.168.1.0/24".parse()?) {
482    ///     Entry::Vacant(mut e) => assert_eq!(e.insert_with(|| 10), &10),
483    ///     Entry::Occupied(_) => unreachable!(),
484    /// }
485    /// assert_eq!(pm.get(&"192.168.1.0/24".parse()?), Some(&10));
486    /// # Ok(())
487    /// # }
488    /// # #[cfg(not(feature = "ipnet"))]
489    /// # fn main() {}
490    /// ```
491    pub fn insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T {
492        let node = self._insert(default());
493        node.value.as_mut().unwrap()
494    }
495}
496
497impl<'a, P, T> VacantEntry<'a, P, T>
498where
499    P: Prefix,
500    T: Default,
501{
502    /// Get a mutable reference to the value. If the value is yet empty, set it to the default value
503    /// using `Default::default()`.
504    ///
505    /// ```
506    /// # use prefix_trie::*;
507    /// use prefix_trie::map::Entry;
508    /// # #[cfg(feature = "ipnet")]
509    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
510    /// let mut pm: PrefixMap<ipnet::Ipv4Net, i32> = PrefixMap::new();
511    /// match pm.entry("192.168.1.0/24".parse()?) {
512    ///     Entry::Vacant(e) => assert_eq!(e.default(), &0),
513    ///     Entry::Occupied(_) => unreachable!(),
514    /// }
515    /// assert_eq!(pm.get(&"192.168.1.0/24".parse()?), Some(&0));
516    /// # Ok(())
517    /// # }
518    /// # #[cfg(not(feature = "ipnet"))]
519    /// # fn main() {}
520    /// ```
521    pub fn default(self) -> &'a mut T {
522        let node = self._insert(Default::default());
523        node.value.as_mut().unwrap()
524    }
525}