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}