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}