overlay_map/lib.rs
1//! A two-layered map structure where the foreground is mutable and the
2//! background is preserved.
3//!
4//! OverlayMap lets you insert values without cloning, while keeping a single
5//! layer of historical context. Each key has a current value (foreground) and
6//! may have a previous value (background), which is automatically managed
7//! during updates.
8//!
9//! ```rust
10//! use overlay_map::Overlay;
11//!
12//! let mut door = Overlay::new_fg("Alice");
13//! println!("Present: {:?}, {:?}", door.fg(), door.bg());
14//!
15//! for name in ["Bob", "Carol", "Dave", "Eve"] {
16//! if let Some(evicted) = door.swap(name) {
17//! println!("{evicted} left");
18//! }
19//! println!("Present: {:?}, {:?}", door.bg(), door.fg());
20//! }
21//!
22//! while let Some(pulled) = door.pull() {
23//! println!("{pulled} left");
24//! }
25//!
26//! println!("Present: {:?}, {:?}", door.bg(), door.fg());
27//! ```
28
29use std::{
30 hash::{BuildHasher, Hash},
31 mem::MaybeUninit,
32};
33
34use hashbrown::{DefaultHashBuilder, HashMap, hash_map::RawEntryMut};
35
36/// A two-layered map where each key has a mutable foreground and an optional
37/// background value.
38///
39/// When inserting a new value for a key, the previous value (if any) is
40/// automatically moved to the background. Background values are preserved but
41/// not cloned.
42///
43/// This map is not thread-safe for mutation. It may be shared across threads
44/// for read-only access.
45#[derive(Debug, Default)]
46pub struct OverlayMap<K, V, S = DefaultHashBuilder>
47where
48 K: Eq + Hash,
49{
50 map: HashMap<K, Overlay<V>, S>,
51}
52
53unsafe impl<K, V, S> Sync for OverlayMap<K, V, S>
54where
55 K: Eq + Hash + Sync,
56 S: Sync,
57{
58}
59
60impl<K, V, S> OverlayMap<K, V, S>
61where
62 K: Eq + Hash,
63 S: BuildHasher + Default,
64{
65 /// Creates a new, empty `OverlayMap` with the default hasher.
66 pub fn new() -> Self {
67 Self::with_hasher(Default::default())
68 }
69
70 /// Creates an empty `OverlayMap` with the specified capacity and default hasher.
71 pub fn with_capacity(capacity: usize) -> Self {
72 Self::with_capacity_and_hasher(capacity, Default::default())
73 }
74
75 /// Creates an empty `OverlayMap` that will use the given hasher.
76 pub fn with_hasher(hasher: S) -> Self {
77 Self {
78 map: HashMap::with_hasher(hasher),
79 }
80 }
81
82 /// Creates an empty `OverlayMap` with the specified capacity and hasher.
83 pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
84 Self {
85 map: HashMap::with_capacity_and_hasher(capacity, hasher),
86 }
87 }
88
89 /// Number of unique keys in the map.
90 pub fn len(&self) -> usize {
91 self.map.len()
92 }
93
94 /// Check if the map is empty.
95 pub fn is_empty(&self) -> bool {
96 self.map.is_empty()
97 }
98
99 /// Get an immutable reference to the value associated with the key.
100 ///
101 /// Returns `None` if the key was not found in the map.
102 #[inline]
103 pub fn fg(&self, key: &K) -> Option<&V> {
104 self.map.get(key).map(|entry| entry.fg_unchecked())
105 }
106
107 /// Get an immutable reference to the value associated with the key in the background layer.
108 ///
109 /// Returns `None` if the key was not found in the background layer.
110 #[inline]
111 pub fn bg(&self, key: &K) -> Option<&V> {
112 self.map.get(key).and_then(|entry| entry.bg())
113 }
114
115 /// Push a value into the foreground layer, preserving the previous value in
116 /// the background.
117 ///
118 /// If the key was already present, the current foreground is moved to the
119 /// background slot, and the new value becomes the new foreground. No
120 /// cloning occurs. The old background value is dropped if it was present.
121 ///
122 /// Returns `true` if there was already a foreground value (i.e. a
123 /// background now definitely exists).
124 #[inline]
125 pub fn push(&mut self, key: K, value: V) -> bool {
126 match self.map.raw_entry_mut().from_key(&key) {
127 RawEntryMut::Occupied(mut occupied) => {
128 occupied.get_mut().push(value);
129 true
130 }
131 RawEntryMut::Vacant(vacant) => {
132 vacant.insert(key, Overlay::new_fg(value));
133 false
134 }
135 }
136 }
137
138 /// Conditionally push a new value into the foreground based on the current
139 /// value.
140 ///
141 /// If the key exists, the current foreground value is passed to the
142 /// predicate. If the predicate returns `Some(new_val)`, the new value is
143 /// pushed and the old one is preserved in the background. If it returns
144 /// `None`, nothing is changed.
145 ///
146 /// Returns `true` if a new value was pushed.
147 pub fn push_if<F>(&mut self, key: &K, predicate: F) -> bool
148 where
149 F: FnOnce(&V) -> Option<V>,
150 {
151 let entry = match self.map.get_mut(key) {
152 Some(e) => e,
153 None => return false,
154 };
155
156 match predicate(entry.fg_unchecked()) {
157 Some(new) => {
158 entry.push(new);
159 true
160 }
161 None => false,
162 }
163 }
164
165 /// Pulls the foreground value for a key, promoting the background to foreground if present.
166 ///
167 /// This removes and returns the current foreground value for the given key. If a background
168 /// value exists, it is promoted to foreground. If the key has no background after the pull,
169 /// the key is removed from the map entirely.
170 ///
171 /// # Returns
172 ///
173 /// - `Some(value)` if the key existed and a foreground value was pulled.
174 /// - `None` if the key did not exist.
175 ///
176 /// # Invariants
177 ///
178 /// - After this operation, the key is only retained if a background value was available
179 /// to promote.
180 /// - Keys in the map always have at least one value (foreground), unless removed by `pull`.
181 ///
182 /// # Example
183 ///
184 /// ```
185 /// use overlay_map::OverlayMap;
186 ///
187 /// let mut map = OverlayMap::<&str, i32>::new();
188 /// map.push("key", 1);
189 /// map.push("key", 2);
190 ///
191 /// assert_eq!(map.fg(&"key"), Some(&2));
192 /// assert_eq!(map.bg(&"key"), Some(&1));
193 ///
194 /// let pulled = map.pull(&"key");
195 /// assert_eq!(pulled, Some(2));
196 /// assert_eq!(map.fg(&"key"), Some(&1)); // background promoted
197 ///
198 /// let pulled = map.pull(&"key");
199 /// assert_eq!(pulled, Some(1));
200 /// assert_eq!(map.fg(&"key"), None); // entry removed
201 /// ```
202 #[inline]
203 pub fn pull(&mut self, key: &K) -> Option<V> {
204 match self.map.raw_entry_mut().from_key(key) {
205 RawEntryMut::Occupied(mut occupied) => {
206 let entry = occupied.get_mut();
207 let evicted = entry.pull_unchecked();
208 if entry.is_empty() {
209 occupied.remove();
210 }
211 Some(evicted)
212 }
213 RawEntryMut::Vacant(_) => None,
214 }
215 }
216
217 /// Conditionally pulls the foreground value for a key, promoting the background if present.
218 ///
219 /// If the key exists and the provided predicate returns `true` for the current foreground,
220 /// this removes and returns the foreground value. The background (if any) is promoted to
221 /// foreground, and the key is removed from the map if no background remains.
222 ///
223 /// If the predicate returns `false` or the key does not exist, the map is left unchanged.
224 ///
225 /// # Returns
226 ///
227 /// - `Some(value)` if the predicate matched and the foreground was pulled.
228 /// - `None` if the key was not found or the predicate returned `false`.
229 ///
230 /// # Invariants
231 ///
232 /// - After this operation, the key is only retained if a background value was available
233 /// to promote.
234 /// - Keys in the map always have at least one value (foreground), unless removed by `pull_if`.
235 ///
236 /// # Example
237 ///
238 /// ```
239 /// use overlay_map::OverlayMap;
240 ///
241 /// let mut map = OverlayMap::<&str, i32>::new();
242 /// map.push("key", 10);
243 /// map.push("key", 20);
244 ///
245 /// // Only pull if the foreground is 20
246 /// let pulled = map.pull_if(&"key", |v| *v == 20);
247 /// assert_eq!(pulled, Some(20));
248 /// assert_eq!(map.fg(&"key"), Some(&10));
249 ///
250 /// // Predicate does not match: nothing is pulled
251 /// let pulled = map.pull_if(&"key", |v| *v == 999);
252 /// assert_eq!(pulled, None);
253 /// assert_eq!(map.fg(&"key"), Some(&10));
254 ///
255 /// // Pull remaining value, removing the key
256 /// let pulled = map.pull_if(&"key", |_| true);
257 /// assert_eq!(pulled, Some(10));
258 /// assert_eq!(map.fg(&"key"), None);
259 /// ```
260 pub fn pull_if<F>(&mut self, key: &K, predicate: F) -> Option<V>
261 where
262 F: FnOnce(&V) -> bool,
263 {
264 match self.map.raw_entry_mut().from_key(key) {
265 RawEntryMut::Occupied(mut occupied) => {
266 let entry = occupied.get_mut();
267 if predicate(entry.fg_unchecked()) {
268 let evicted = entry.pull_unchecked();
269 if entry.is_empty() {
270 occupied.remove();
271 }
272 Some(evicted)
273 } else {
274 None
275 }
276 }
277 RawEntryMut::Vacant(_) => None,
278 }
279 }
280
281 /// Swap a value into the foreground layer, preserving the previous value in
282 /// the background, and returning the evicted background value if present.
283 ///
284 /// If the key was already present, the current foreground is moved to the
285 /// background slot, and the new value becomes the new foreground. No
286 /// cloning occurs. The old background value is returned if present.
287 #[inline]
288 pub fn swap(&mut self, key: K, value: V) -> Option<V> {
289 match self.map.raw_entry_mut().from_key(&key) {
290 RawEntryMut::Occupied(mut occupied) => occupied.get_mut().swap(value),
291 RawEntryMut::Vacant(vacant) => {
292 vacant.insert(key, Overlay::new_fg(value));
293 None
294 }
295 }
296 }
297
298 /// Conditionally swap a new value into the foreground based on the current
299 /// value.
300 ///
301 /// If the key exists, the current foreground value is passed to the
302 /// predicate. If the predicate returns `Some(new_val)`, the new value is
303 /// pushed and the old one is preserved in the background. If it returns
304 /// `None`, nothing is changed.
305 ///
306 /// The evicted background value is returned if present.
307 pub fn swap_if<F>(&mut self, key: &K, predicate: F) -> Option<V>
308 where
309 F: FnOnce(&V) -> Option<V>,
310 {
311 let entry = self.map.get_mut(key)?;
312 match predicate(entry.fg_unchecked()) {
313 Some(new) => entry.swap(new),
314 None => None,
315 }
316 }
317
318 /// Overlay multiple values onto the map.
319 ///
320 /// Each key-value pair is pushed into the foreground layer. If the key was
321 /// already present, the existing foreground value is moved to the
322 /// background. This does not clone or retain old values beyond the
323 /// background layer.
324 ///
325 /// Returns the number of keys that already existed (i.e. pushes that
326 /// replaced a foreground).
327 pub fn overlay<I>(&mut self, iter: I) -> usize
328 where
329 I: IntoIterator<Item = (K, V)>,
330 {
331 let mut replaced = 0;
332 for (key, val) in iter {
333 replaced += self.push(key, val) as usize;
334 }
335 replaced
336 }
337}
338
339const SLOT0_PRESENT: u8 = 1 << 0;
340const SLOT1_PRESENT: u8 = 1 << 1;
341const FG_SLOT: u8 = 1 << 2;
342
343/// A two-layer value container used by [`OverlayMap`] to manage current and historical values.
344///
345/// `Overlay<T>` stores up to two values:
346///
347/// - A **foreground** value representing the current state.
348/// - An optional **background** value representing the previous state.
349///
350/// When used through [`OverlayMap`], each key maps to an `Overlay<T>` to track updates
351/// without requiring clones or reallocations. You can also use `Overlay<T>` standalone
352/// to manage two-layer state transitions for any value type.
353///
354/// Values are moved, never cloned. All operations (push, pull, swap) are zero-cost and
355/// memory-efficient.
356///
357/// # Use Cases
358///
359/// - Managing current and previous state in UI or simulation logic
360/// - Efficient delta tracking for configs, game state, etc.
361/// - Avoiding `Option<(T, T)>` or custom wrappers with cloning overhead
362///
363/// # Examples
364///
365/// ```
366/// use overlay_map::Overlay;
367///
368/// let mut entry = Overlay::new_fg("current");
369/// entry.push("next"); // moves "current" into background
370///
371/// assert_eq!(entry.fg(), Some(&"next"));
372/// assert_eq!(entry.bg(), Some(&"current"));
373///
374/// let pulled = entry.pull();
375/// assert_eq!(pulled, Some("next"));
376/// assert_eq!(entry.fg(), Some(&"current"));
377/// ```
378///
379/// [`OverlayMap`]: crate::OverlayMap
380#[derive(Debug)]
381pub struct Overlay<T> {
382 bits: u8,
383 slots: [MaybeUninit<T>; 2],
384}
385
386impl<T> Overlay<T> {
387 /// Creates a new `Overlay` with no values.
388 pub fn new_empty() -> Self {
389 Self {
390 bits: 0,
391 slots: [MaybeUninit::uninit(), MaybeUninit::uninit()],
392 }
393 }
394
395 /// Creates a new `Overlay` with a foreground value and no background.
396 pub fn new_fg(val: T) -> Self {
397 Self {
398 bits: SLOT0_PRESENT,
399 slots: [MaybeUninit::new(val), MaybeUninit::uninit()],
400 }
401 }
402
403 /// Creates a new `Overlay` with both foreground and background values.
404 pub fn new_both(fg: T, bg: T) -> Self {
405 Self {
406 bits: SLOT0_PRESENT | SLOT1_PRESENT,
407 slots: [MaybeUninit::new(fg), MaybeUninit::new(bg)],
408 }
409 }
410
411 /// Returns a reference to the current foreground value, if present.
412 ///
413 /// This returns `Some(&T)` only if the foreground slot contains a value.
414 /// If the slot is logically empty, returns `None`. This is a safe version that
415 /// checks the presence bits before accessing memory.
416 ///
417 /// # Safety
418 /// This function is fully safe and performs a presence check before dereferencing.
419 ///
420 /// # Returns
421 /// - `Some(&T)` if the foreground slot is initialized
422 /// - `None` if the foreground slot is uninitialized
423 #[inline]
424 pub fn fg(&self) -> Option<&T> {
425 let idx = self.fg_index();
426 if self.is_slot_present(idx) {
427 Some(unsafe { self.slots[idx].assume_init_ref() })
428 } else {
429 None
430 }
431 }
432
433 /// Returns a reference to the foreground value **without checking** if it is present.
434 ///
435 /// # Safety
436 /// This function **assumes** the foreground slot is initialized. Calling this when
437 /// the slot is uninitialized (i.e. after a `pull()` without a background, or
438 /// after constructing an empty `Overlay`) results in **undefined behavior**.
439 ///
440 /// Use [`fg`](Self::fg) if you are not certain the slot is populated.
441 ///
442 /// # Panics
443 /// Never panics, but causes UB if the foreground slot is not present.
444 #[inline]
445 pub fn fg_unchecked(&self) -> &T {
446 let idx = self.fg_index();
447 unsafe { self.slots[idx].assume_init_ref() }
448 }
449
450 /// Returns a reference to the background value, if present.
451 ///
452 /// Returns `Some(&T)` only if the background slot is initialized.
453 #[inline]
454 pub fn bg(&self) -> Option<&T> {
455 let idx = self.bg_index();
456 if self.is_slot_present(idx) {
457 Some(unsafe { self.slots[idx].assume_init_ref() })
458 } else {
459 None
460 }
461 }
462
463 /// Returns a reference to the background value **without checking** if it is present.
464 ///
465 /// # Safety
466 /// This assumes the background slot is initialized. Calling this when it is not
467 /// will cause **undefined behavior**.
468 ///
469 /// Prefer [`bg`](Self::bg) if you're unsure whether the background is set.
470 #[inline]
471 pub fn bg_unchecked(&self) -> &T {
472 let idx = self.bg_index();
473 unsafe { self.slots[idx].assume_init_ref() }
474 }
475
476 /// Returns `true` if both slots are empty.
477 ///
478 /// This is used to determine whether the entry contains any values
479 /// at all. It does not consider which slot is foreground or background.
480 #[inline]
481 pub fn is_empty(&self) -> bool {
482 (self.bits & (SLOT0_PRESENT | SLOT1_PRESENT)) == 0
483 }
484
485 /// Push a value into the foreground layer, preserving the previous foreground in the background.
486 ///
487 /// If the foreground slot already contains a value, it is moved into the background slot.
488 /// The new value is then written into the foreground slot. Any previous background value
489 /// will be dropped to make room—no cloning is performed at any point.
490 ///
491 /// This operation is always safe, even if the entry is empty. If no foreground is currently
492 /// present, the value will simply be inserted.
493 ///
494 /// # Example
495 /// ```
496 /// use overlay_map::Overlay;
497 /// let mut entry = Overlay::new_fg("a");
498 /// entry.push("b");
499 /// assert_eq!(entry.fg(), Some(&"b"));
500 /// assert_eq!(entry.bg(), Some(&"a"));
501 /// ```
502 #[inline]
503 pub fn push(&mut self, val: T) {
504 self.push_fg_to_bg();
505 let idx = self.fg_index();
506 self.slots[idx] = MaybeUninit::new(val);
507 self.bits |= 1 << idx;
508 }
509
510 /// Safely pull the current foreground value out, promoting the background to foreground if present.
511 ///
512 /// If the foreground value is present, it is removed and returned. The background (if any) is
513 /// promoted to the foreground. If neither value remains, the entry becomes empty.
514 ///
515 /// Returns `None` if the foreground was not present.
516 ///
517 /// # Example
518 /// ```
519 /// use overlay_map::Overlay;
520 /// let mut entry = Overlay::new_both("a", "b");
521 /// let pulled = entry.pull();
522 /// assert_eq!(pulled, Some("a"));
523 /// assert_eq!(entry.fg(), Some(&"b")); // background promoted
524 /// ```
525 #[inline]
526 pub fn pull(&mut self) -> Option<T> {
527 let fgi = self.fg_index();
528 if !self.is_slot_present(fgi) {
529 return None;
530 }
531
532 let evicted = unsafe { self.slots[fgi].assume_init_read() };
533 self.bits &= !(1 << fgi);
534 self.flip();
535 Some(evicted)
536 }
537
538 /// Pull the current foreground value without checking if it is present.
539 ///
540 /// # Safety
541 /// The caller must ensure the foreground slot is present. If it is not, this will result
542 /// in undefined behavior.
543 ///
544 /// See [`Self::pull`] for a safe alternative.
545 #[inline]
546 pub fn pull_unchecked(&mut self) -> T {
547 let fgi = self.fg_index();
548 let evicted = unsafe { self.slots[fgi].assume_init_read() };
549 self.bits &= !(1 << fgi);
550 self.flip();
551 evicted
552 }
553
554 /// Swap in a new foreground value, returning the old background if present.
555 ///
556 /// If a background value exists, it is evicted and returned. The new value is written into
557 /// the background slot, which is then promoted to become the new foreground. The current
558 /// foreground is preserved in-place.
559 ///
560 /// If no background was present, this behaves like a standard push operation,
561 /// and `None` is returned.
562 ///
563 /// # Example
564 /// ```
565 /// use overlay_map::Overlay;
566 /// let mut entry = Overlay::new_both("a", "b");
567 /// let evicted = entry.swap("c");
568 /// assert_eq!(evicted, Some("b"));
569 /// assert_eq!(entry.fg(), Some(&"c"));
570 /// assert_eq!(entry.bg(), Some(&"a"));
571 /// ```
572 #[inline]
573 pub fn swap(&mut self, val: T) -> Option<T> {
574 let bgi = self.bg_index();
575 if self.is_slot_present(bgi) {
576 let evicted = unsafe { self.slots[bgi].assume_init_read() };
577 self.slots[bgi] = MaybeUninit::new(val);
578 self.flip();
579 Some(evicted)
580 } else {
581 self.push(val);
582 None
583 }
584 }
585
586 #[inline]
587 fn fg_index(&self) -> usize {
588 ((self.bits & FG_SLOT) >> 2) as usize
589 }
590
591 #[inline]
592 fn bg_index(&self) -> usize {
593 self.fg_index() ^ 1
594 }
595
596 #[inline]
597 fn is_slot_present(&self, idx: usize) -> bool {
598 (self.bits & (1 << idx)) != 0
599 }
600
601 /// Moves the current foreground value to the background slot, dropping any
602 /// previous background.
603 ///
604 /// This operation updates only internal bits and memory slots. The value
605 /// itself is not cloned or moved in memory. If a background value already
606 /// exists, it is dropped before being replaced.
607 #[inline]
608 fn push_fg_to_bg(&mut self) {
609 let bgi = self.bg_index();
610 if self.is_slot_present(bgi) {
611 unsafe {
612 self.slots[bgi].assume_init_drop();
613 }
614 }
615 self.flip();
616 }
617
618 /// Flip the foreground/background logical mapping
619 #[inline]
620 fn flip(&mut self) {
621 self.bits ^= FG_SLOT;
622 }
623}
624
625impl<V> Drop for Overlay<V> {
626 fn drop(&mut self) {
627 if (self.bits & SLOT0_PRESENT) != 0 {
628 unsafe { self.slots[0].assume_init_drop() };
629 }
630
631 if (self.bits & SLOT1_PRESENT) != 0 {
632 unsafe { self.slots[1].assume_init_drop() };
633 }
634 }
635}
636
637#[cfg(test)]
638mod tests {
639 use super::*;
640
641 #[test]
642 fn push_and_get_foreground() {
643 let mut map = OverlayMap::<&str, i32>::new();
644 assert!(map.fg(&"key").is_none());
645 map.push("key", 42);
646 assert_eq!(*map.fg(&"key").expect("Entry was just pushed"), 42);
647 }
648
649 #[test]
650 fn push_and_get_background() {
651 let mut map = OverlayMap::<&str, i32>::new();
652 assert!(map.fg(&"key").is_none());
653 map.push("key", 99);
654 assert_eq!(*map.fg(&"key").expect("Entry was just pushed"), 99);
655 }
656
657 #[test]
658 fn push_if_no_change_foreground() {
659 let mut map = OverlayMap::<&str, i32>::new();
660 map.push("key", 100);
661
662 // Try swap but do nothing
663 map.push_if(&"key", |old| {
664 if *old == 100 {
665 None // no change
666 } else {
667 Some(999)
668 }
669 });
670
671 // Still foreground = 100, no background
672 assert_eq!(*map.fg(&"key").expect("Entry should still exist"), 100);
673 }
674
675 #[test]
676 fn push_if_foreground_to_background() {
677 let mut map = OverlayMap::<&str, i32>::new();
678 map.push("key", 50);
679 map.push_if(&"key", |old| if *old == 50 { Some(123) } else { None });
680 assert_eq!(*map.fg(&"key").expect("Entry should still exist"), 123);
681 assert_eq!(
682 *map.bg(&"key").expect("Old value not found in background"),
683 50
684 );
685 }
686
687 #[test]
688 fn push_if_missing_key() {
689 let mut map = OverlayMap::<&str, i32>::new();
690 map.push_if(&"missing", |_| Some(999));
691 assert!(map.fg(&"missing").is_none());
692 }
693
694 #[test]
695 fn pull_with_remainder_test() {
696 let mut map = OverlayMap::<&str, i32>::new();
697 map.push("key", 42);
698 map.push("key", 24);
699 assert_eq!(Some(&24), map.fg(&"key"));
700 assert_eq!(Some(&42), map.bg(&"key"));
701 assert_eq!(Some(24), map.pull(&"key"));
702 assert_eq!(Some(&42), map.fg(&"key"));
703 assert_eq!(None, map.bg(&"key"));
704 assert_eq!(1, map.len());
705 }
706
707 #[test]
708 fn pull_without_remainder_test() {
709 let mut map = OverlayMap::<&str, i32>::new();
710 map.push("key", 42);
711 assert_eq!(Some(&42), map.fg(&"key"));
712 assert_eq!(Some(42), map.pull(&"key"));
713 assert_eq!(None, map.fg(&"key"));
714 assert_eq!(None, map.bg(&"key"));
715 assert_eq!(0, map.len());
716 }
717
718 #[test]
719 fn swap_test() {
720 let mut map = OverlayMap::<&str, i32>::new();
721 map.push("key", 42);
722 assert_eq!(*map.fg(&"key").expect("Entry was just pushed"), 42);
723 assert_eq!(None, map.swap("key", 100));
724 let old_value = map.swap("key", 150);
725 assert_eq!(old_value, Some(42));
726 assert_eq!(*map.fg(&"key").expect("Entry was just pushed"), 150);
727 assert_eq!(*map.bg(&"key").expect("Entry was just pushed"), 100);
728 }
729
730 #[test]
731 fn swap_if_test() {
732 let mut map = OverlayMap::<&str, i32>::new();
733 map.push("key", 50);
734 map.push("key", 100);
735 let evicted = map.swap_if(&"key", |old| if *old == 100 { Some(123) } else { None });
736 assert_eq!(*map.fg(&"key").expect("Entry should still exist"), 123);
737 assert_eq!(*map.bg(&"key").expect("Entry should still exist"), 100);
738 assert_eq!(evicted, Some(50));
739 }
740
741 #[test]
742 fn overlay_test() {
743 // Initialize an OverlayMap with:
744 // - "fg_key" in foreground
745 // - "bg_key" in background
746 // - "absent_key" absent
747 let mut map = OverlayMap::<&str, i32>::new();
748 map.push("fg_key", 10);
749 map.push("bg_key", 20);
750
751 // Prepare updates:
752 // - "fg_key" -> 100
753 // - "bg_key" -> 200
754 // - "none_key" -> 300 (was absent in map)
755 let updates = vec![("fg_key", 100), ("bg_key", 200), ("none_key", 300)];
756
757 // Perform the merge
758 map.overlay(updates);
759
760 // Check that "fg_key" was in foreground, so old value (10) moved to background.
761 // New value (100) should be in foreground.
762 match map.fg(&"fg_key") {
763 Some(val) => assert_eq!(*val, 100),
764 _ => panic!("Expected 'fg_key' = 100 in foreground"),
765 }
766 match map.bg(&"fg_key") {
767 Some(val) => assert_eq!(*val, 10),
768 None => panic!("Expected old 'fg_key' value = 10 in background"),
769 }
770
771 // Check that "none_key" was absent, so it is now in the foreground with 300
772 match map.fg(&"none_key") {
773 Some(val) => assert_eq!(*val, 300),
774 _ => panic!("Expected 'none_key' = 300 in foreground"),
775 }
776 // It shouldn't exist in background
777 assert!(map.bg(&"none_key").is_none());
778 }
779}