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}