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. This will also
57    /// replace the key with the one provided to the `entry` function.
58    ///
59    /// ```
60    /// # use prefix_trie::joint::*;
61    /// # #[cfg(feature = "ipnet")]
62    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
63    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
64    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).insert(1), None);
65    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).insert(2), Some(1));
66    /// # Ok(())
67    /// # }
68    /// # #[cfg(not(feature = "ipnet"))]
69    /// # fn main() {}
70    /// ```
71    ///
72    /// This function *will replace* the prefix in the map with the one provided to the `entry` call:
73    ///
74    /// ```
75    /// # use prefix_trie::joint::*;
76    /// # #[cfg(feature = "ipnet")]
77    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
78    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
79    /// pm.insert("192.168.1.1/24".parse()?, 1);
80    /// pm.entry("192.168.1.2/24".parse()?).insert(2);
81    /// assert_eq!(
82    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
83    ///     Some(("192.168.1.2/24".parse()?, &2)) // prefix is overwritten
84    /// );
85    /// # Ok(())
86    /// # }
87    /// # #[cfg(not(feature = "ipnet"))]
88    /// # fn main() {}
89    /// ```
90    #[inline(always)]
91    pub fn insert(self, v: T) -> Option<T> {
92        match self {
93            Entry::Vacant(e) => {
94                e.insert(v);
95                None
96            }
97            Entry::Occupied(e) => Some(e.insert(v)),
98        }
99    }
100
101    /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable
102    /// reference to the value in the entry.
103    ///
104    /// ```
105    /// # use prefix_trie::joint::*;
106    /// # #[cfg(feature = "ipnet")]
107    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
108    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
109    /// pm.insert("192.168.1.0/24".parse()?, 1);
110    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).or_insert(10), &1);
111    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).or_insert(20), &20);
112    /// # Ok(())
113    /// # }
114    /// # #[cfg(not(feature = "ipnet"))]
115    /// # fn main() {}
116    /// ```
117    ///
118    /// This function will *not* replace the prefix in the map if it already exists.
119    ///
120    /// ```
121    /// # use prefix_trie::joint::*;
122    /// # #[cfg(feature = "ipnet")]
123    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
124    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
125    /// pm.insert("192.168.1.1/24".parse()?, 1);
126    /// pm.entry("192.168.1.2/24".parse()?).or_insert(2);
127    /// assert_eq!(
128    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
129    ///     Some(("192.168.1.1/24".parse()?, &1)) // prefix is not overwritten.
130    /// );
131    /// # Ok(())
132    /// # }
133    /// # #[cfg(not(feature = "ipnet"))]
134    /// # fn main() {}
135    /// ```
136    #[inline(always)]
137    pub fn or_insert(self, default: T) -> &'a mut T {
138        match self {
139            Entry::Vacant(e) => e.insert(default),
140            Entry::Occupied(e) => match e {
141                OccupiedEntry::P1(e) => e.node.value.get_or_insert(default),
142                OccupiedEntry::P2(e) => e.node.value.get_or_insert(default),
143            },
144        }
145    }
146
147    /// Ensures a value is in the entry by inserting the result of the default function if empty,
148    /// and returns a mutable reference to the value in the entry.
149    ///
150    /// ```
151    /// # use prefix_trie::joint::*;
152    /// # #[cfg(feature = "ipnet")]
153    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
154    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
155    /// pm.insert("192.168.1.0/24".parse()?, 1);
156    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).or_insert_with(|| 10), &1);
157    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).or_insert_with(|| 20), &20);
158    /// # Ok(())
159    /// # }
160    /// # #[cfg(not(feature = "ipnet"))]
161    /// # fn main() {}
162    /// ```
163    ///
164    /// This function will *not* replace the prefix in the map if it already exists.
165    ///
166    /// ```
167    /// # use prefix_trie::joint::*;
168    /// # #[cfg(feature = "ipnet")]
169    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
170    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
171    /// pm.insert("192.168.1.1/24".parse()?, 1);
172    /// pm.entry("192.168.1.2/24".parse()?).or_insert_with(|| 2);
173    /// assert_eq!(
174    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
175    ///     Some(("192.168.1.1/24".parse()?, &1)) // prefix is not overwritten.
176    /// );
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()),
186            Entry::Occupied(e) => match e {
187                OccupiedEntry::P1(e) => e.node.value.get_or_insert_with(default),
188                OccupiedEntry::P2(e) => e.node.value.get_or_insert_with(default),
189            },
190        }
191    }
192
193    /// Provides in-place mutable access to an occupied entry before any potential inserts into the
194    /// map.
195    ///
196    /// ```
197    /// # use prefix_trie::joint::*;
198    /// # #[cfg(feature = "ipnet")]
199    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
200    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
201    /// pm.insert("192.168.1.0/24".parse()?, 1);
202    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).and_modify(|x| *x += 1).get(), Some(&2));
203    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).and_modify(|x| *x += 1).get(), None);
204    /// # Ok(())
205    /// # }
206    /// # #[cfg(not(feature = "ipnet"))]
207    /// # fn main() {}
208    /// ```
209    ///
210    /// This function will *not* replace the prefix in the map if it already exists.
211    ///
212    /// ```
213    /// # use prefix_trie::joint::*;
214    /// # #[cfg(feature = "ipnet")]
215    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
216    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
217    /// pm.insert("192.168.1.1/24".parse()?, 1);
218    /// pm.entry("192.168.1.2/24".parse()?).and_modify(|x| *x += 1);
219    /// assert_eq!(
220    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
221    ///     Some(("192.168.1.1/24".parse()?, &2)) // prefix is not overwritten.
222    /// );
223    /// # Ok(())
224    /// # }
225    /// # #[cfg(not(feature = "ipnet"))]
226    /// # fn main() {}
227    /// ```
228    #[inline(always)]
229    pub fn and_modify<F: FnOnce(&mut T)>(self, f: F) -> Self {
230        match self {
231            Entry::Vacant(e) => Entry::Vacant(e),
232            Entry::Occupied(e) => match e {
233                OccupiedEntry::P1(e) => {
234                    e.node.value.as_mut().map(f);
235                    Entry::Occupied(OccupiedEntry::P1(e))
236                }
237                OccupiedEntry::P2(e) => {
238                    e.node.value.as_mut().map(f);
239                    Entry::Occupied(OccupiedEntry::P2(e))
240                }
241            },
242        }
243    }
244}
245
246impl<'a, P, T> Entry<'a, P, T>
247where
248    P: JointPrefix,
249    T: Default,
250{
251    /// Ensures a value is in the entry by inserting the default value if empty, and returns a
252    /// mutable reference to the value in the entry.
253    ///
254    /// ```
255    /// # use prefix_trie::joint::*;
256    /// # #[cfg(feature = "ipnet")]
257    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
258    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
259    /// pm.insert("192.168.1.0/24".parse()?, 1);
260    /// assert_eq!(pm.entry("192.168.1.0/24".parse()?).or_default(), &1);
261    /// assert_eq!(pm.entry("192.168.2.0/24".parse()?).or_default(), &0);
262    /// # Ok(())
263    /// # }
264    /// # #[cfg(not(feature = "ipnet"))]
265    /// # fn main() {}
266    /// ```
267    ///
268    /// This function will *not* replace the prefix in the map if it already exists.
269    ///
270    /// ```
271    /// # use prefix_trie::joint::*;
272    /// # #[cfg(feature = "ipnet")]
273    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
274    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
275    /// pm.insert("192.168.1.1/24".parse()?, 1);
276    /// pm.entry("192.168.1.2/24".parse()?).or_default();
277    /// assert_eq!(
278    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
279    ///     Some(("192.168.1.1/24".parse()?, &1)) // prefix is not overwritten.
280    /// );
281    /// # Ok(())
282    /// # }
283    /// # #[cfg(not(feature = "ipnet"))]
284    /// # fn main() {}
285    /// ```
286    #[allow(clippy::unwrap_or_default)]
287    #[inline(always)]
288    pub fn or_default(self) -> &'a mut T {
289        self.or_insert_with(Default::default)
290    }
291}
292
293impl<P: JointPrefix, T> OccupiedEntry<'_, P, T> {
294    /// Gets a reference to the key in the entry. This is the key that is currently stored, and not
295    /// the key that was used in the insert.
296    pub fn key(&self) -> P {
297        match self {
298            OccupiedEntry::P1(e) => P::from_p1(e.key()),
299            OccupiedEntry::P2(e) => P::from_p2(e.key()),
300        }
301    }
302
303    /// Gets a reference to the value in the entry.
304    pub fn get(&self) -> &T {
305        match self {
306            OccupiedEntry::P1(e) => e.get(),
307            OccupiedEntry::P2(e) => e.get(),
308        }
309    }
310
311    /// Gets a mutable reference to the value in the entry.
312    ///
313    /// This call will not modify the prefix stored in the tree. In case the prefix used to create
314    /// the entry is different from the stored one (has additional information in the host part),
315    /// and you wish that prefix to be overwritten, use `insert`.
316    ///
317    /// ```
318    /// # use prefix_trie::joint::*;
319    /// use prefix_trie::joint::map::Entry;
320    /// # #[cfg(feature = "ipnet")]
321    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
322    /// let mut pm: JointPrefixMap<ipnet::IpNet, _> = JointPrefixMap::new();
323    /// pm.insert("192.168.1.1/24".parse()?, 1);
324    /// if let Entry::Occupied(mut e) = pm.entry("192.168.1.0/24".parse()?) {
325    ///     *e.get_mut() += 1;
326    /// }
327    /// assert_eq!(
328    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
329    ///     Some(("192.168.1.1/24".parse()?, &2)) // prefix is not overwritten
330    /// );
331    /// # Ok(())
332    /// # }
333    /// # #[cfg(not(feature = "ipnet"))]
334    /// # fn main() {}
335    /// ```
336    pub fn get_mut(&mut self) -> &mut T {
337        match self {
338            OccupiedEntry::P1(e) => e.get_mut(),
339            OccupiedEntry::P2(e) => e.get_mut(),
340        }
341    }
342
343    /// Insert a new value into the entry, returning the old value. This operation will also replace
344    /// the prefix with the provided one.
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); // doing so will overwrite the prefix.
355    /// }
356    /// assert_eq!(
357    ///     pm.get_key_value(&"192.168.1.0/24".parse()?),
358    ///     Some(("192.168.1.0/24".parse()?, &2)) // prefix is overwritten
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. The tree will not be modified (the same effect as
373    /// `JointPrefixMap::remove_keep_tree`).
374    pub fn remove(&mut 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}