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> OverlayMap<K, V, DefaultHashBuilder>
61where
62    K: Eq + Hash,
63{
64    /// Creates a new, empty `OverlayMap` using the default hasher.
65    pub fn new() -> Self {
66        Self::with_hasher(DefaultHashBuilder::default())
67    }
68}
69
70impl<K, V, S> OverlayMap<K, V, S>
71where
72    K: Eq + Hash,
73    S: BuildHasher + Default,
74{
75    /// Creates an empty `OverlayMap` with the specified capacity and default hasher.
76    pub fn with_capacity(capacity: usize) -> Self {
77        Self::with_capacity_and_hasher(capacity, Default::default())
78    }
79
80    /// Creates an empty `OverlayMap` that will use the given hasher.
81    pub fn with_hasher(hasher: S) -> Self {
82        Self {
83            map: HashMap::with_hasher(hasher),
84        }
85    }
86
87    /// Creates an empty `OverlayMap` with the specified capacity and hasher.
88    pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
89        Self {
90            map: HashMap::with_capacity_and_hasher(capacity, hasher),
91        }
92    }
93
94    /// Number of unique keys in the map.
95    pub fn len(&self) -> usize {
96        self.map.len()
97    }
98
99    /// Check if the map is empty.
100    pub fn is_empty(&self) -> bool {
101        self.map.is_empty()
102    }
103
104    /// Get an immutable reference to the value associated with the key.
105    ///
106    /// Returns `None` if the key was not found in the map.
107    #[inline]
108    pub fn fg(&self, key: &K) -> Option<&V> {
109        self.map.get(key).map(|entry| entry.fg_unchecked())
110    }
111
112    /// Get an immutable reference to the value associated with the key in the background layer.
113    ///
114    /// Returns `None` if the key was not found in the background layer.
115    #[inline]
116    pub fn bg(&self, key: &K) -> Option<&V> {
117        self.map.get(key).and_then(|entry| entry.bg())
118    }
119
120    /// Push a value into the foreground layer, preserving the previous value in
121    /// the background.
122    ///
123    /// If the key was already present, the current foreground is moved to the
124    /// background slot, and the new value becomes the new foreground. No
125    /// cloning occurs. The old background value is dropped if it was present.
126    ///
127    /// Returns `true` if there was already a foreground value (i.e. a
128    /// background now definitely exists).
129    #[inline]
130    pub fn push(&mut self, key: K, value: V) -> bool {
131        match self.map.raw_entry_mut().from_key(&key) {
132            RawEntryMut::Occupied(mut occupied) => {
133                occupied.get_mut().push(value);
134                true
135            }
136            RawEntryMut::Vacant(vacant) => {
137                vacant.insert(key, Overlay::new_fg(value));
138                false
139            }
140        }
141    }
142
143    /// Conditionally push a new value into the foreground based on the current
144    /// value.
145    ///
146    /// If the key exists, the current foreground value is passed to the
147    /// predicate. If the predicate returns `Some(new_val)`, the new value is
148    /// pushed and the old one is preserved in the background. If it returns
149    /// `None`, nothing is changed.
150    ///
151    /// Returns `true` if a new value was pushed.
152    pub fn push_if<F>(&mut self, key: &K, predicate: F) -> bool
153    where
154        F: FnOnce(&V) -> Option<V>,
155    {
156        let entry = match self.map.get_mut(key) {
157            Some(e) => e,
158            None => return false,
159        };
160
161        match predicate(entry.fg_unchecked()) {
162            Some(new) => {
163                entry.push(new);
164                true
165            }
166            None => false,
167        }
168    }
169
170    /// Pulls the foreground value for a key, promoting the background to foreground if present.
171    ///
172    /// This removes and returns the current foreground value for the given key. If a background
173    /// value exists, it is promoted to foreground. If the key has no background after the pull,
174    /// the key is removed from the map entirely.
175    ///
176    /// # Returns
177    ///
178    /// - `Some(value)` if the key existed and a foreground value was pulled.
179    /// - `None` if the key did not exist.
180    ///
181    /// # Invariants
182    ///
183    /// - After this operation, the key is only retained if a background value was available
184    ///   to promote.
185    /// - Keys in the map always have at least one value (foreground), unless removed by `pull`.
186    ///
187    /// # Example
188    ///
189    /// ```
190    /// use overlay_map::OverlayMap;
191    ///
192    /// let mut map = OverlayMap::<&str, i32>::new();
193    /// map.push("key", 1);
194    /// map.push("key", 2);
195    ///
196    /// assert_eq!(map.fg(&"key"), Some(&2));
197    /// assert_eq!(map.bg(&"key"), Some(&1));
198    ///
199    /// let pulled = map.pull(&"key");
200    /// assert_eq!(pulled, Some(2));
201    /// assert_eq!(map.fg(&"key"), Some(&1)); // background promoted
202    ///
203    /// let pulled = map.pull(&"key");
204    /// assert_eq!(pulled, Some(1));
205    /// assert_eq!(map.fg(&"key"), None); // entry removed
206    /// ```
207    #[inline]
208    pub fn pull(&mut self, key: &K) -> Option<V> {
209        match self.map.raw_entry_mut().from_key(key) {
210            RawEntryMut::Occupied(mut occupied) => {
211                let entry = occupied.get_mut();
212                let evicted = entry.pull_unchecked();
213                if entry.is_empty() {
214                    occupied.remove();
215                }
216                Some(evicted)
217            }
218            RawEntryMut::Vacant(_) => None,
219        }
220    }
221
222    /// Conditionally pulls the foreground value for a key, promoting the background if present.
223    ///
224    /// If the key exists and the provided predicate returns `true` for the current foreground,
225    /// this removes and returns the foreground value. The background (if any) is promoted to
226    /// foreground, and the key is removed from the map if no background remains.
227    ///
228    /// If the predicate returns `false` or the key does not exist, the map is left unchanged.
229    ///
230    /// # Returns
231    ///
232    /// - `Some(value)` if the predicate matched and the foreground was pulled.
233    /// - `None` if the key was not found or the predicate returned `false`.
234    ///
235    /// # Invariants
236    ///
237    /// - After this operation, the key is only retained if a background value was available
238    ///   to promote.
239    /// - Keys in the map always have at least one value (foreground), unless removed by `pull_if`.
240    ///
241    /// # Example
242    ///
243    /// ```
244    /// use overlay_map::OverlayMap;
245    ///
246    /// let mut map = OverlayMap::<&str, i32>::new();
247    /// map.push("key", 10);
248    /// map.push("key", 20);
249    ///
250    /// // Only pull if the foreground is 20
251    /// let pulled = map.pull_if(&"key", |v| *v == 20);
252    /// assert_eq!(pulled, Some(20));
253    /// assert_eq!(map.fg(&"key"), Some(&10));
254    ///
255    /// // Predicate does not match: nothing is pulled
256    /// let pulled = map.pull_if(&"key", |v| *v == 999);
257    /// assert_eq!(pulled, None);
258    /// assert_eq!(map.fg(&"key"), Some(&10));
259    ///
260    /// // Pull remaining value, removing the key
261    /// let pulled = map.pull_if(&"key", |_| true);
262    /// assert_eq!(pulled, Some(10));
263    /// assert_eq!(map.fg(&"key"), None);
264    /// ```
265    pub fn pull_if<F>(&mut self, key: &K, predicate: F) -> Option<V>
266    where
267        F: FnOnce(&V) -> bool,
268    {
269        match self.map.raw_entry_mut().from_key(key) {
270            RawEntryMut::Occupied(mut occupied) => {
271                let entry = occupied.get_mut();
272                if predicate(entry.fg_unchecked()) {
273                    let evicted = entry.pull_unchecked();
274                    if entry.is_empty() {
275                        occupied.remove();
276                    }
277                    Some(evicted)
278                } else {
279                    None
280                }
281            }
282            RawEntryMut::Vacant(_) => None,
283        }
284    }
285
286    /// Swap a value into the foreground layer, preserving the previous value in
287    /// the background, and returning the evicted background value if present.
288    ///
289    /// If the key was already present, the current foreground is moved to the
290    /// background slot, and the new value becomes the new foreground. No
291    /// cloning occurs. The old background value is returned if present.
292    #[inline]
293    pub fn swap(&mut self, key: K, value: V) -> Option<V> {
294        match self.map.raw_entry_mut().from_key(&key) {
295            RawEntryMut::Occupied(mut occupied) => occupied.get_mut().swap(value),
296            RawEntryMut::Vacant(vacant) => {
297                vacant.insert(key, Overlay::new_fg(value));
298                None
299            }
300        }
301    }
302
303    /// Conditionally swap a new value into the foreground based on the current
304    /// value.
305    ///
306    /// If the key exists, the current foreground value is passed to the
307    /// predicate. If the predicate returns `Some(new_val)`, the new value is
308    /// pushed and the old one is preserved in the background. If it returns
309    /// `None`, nothing is changed.
310    ///
311    /// The evicted background value is returned if present.
312    pub fn swap_if<F>(&mut self, key: &K, predicate: F) -> Option<V>
313    where
314        F: FnOnce(&V) -> Option<V>,
315    {
316        let entry = self.map.get_mut(key)?;
317        match predicate(entry.fg_unchecked()) {
318            Some(new) => entry.swap(new),
319            None => None,
320        }
321    }
322
323    /// Extends the map with a sequence of key-value pairs, counting foreground replacements.
324    ///
325    /// Each `(K, V)` pair is pushed into the foreground. If a key already exists,
326    /// the current foreground is moved to the background, and the new value becomes
327    /// the new foreground. If the key is new, it is inserted without affecting any background.
328    ///
329    /// This method returns the number of keys that were already present — i.e., how many
330    /// pushes replaced an existing foreground value.
331    ///
332    /// No cloning or heap allocation is performed beyond what's necessary for the `HashMap`.
333    ///
334    /// # Example
335    /// ```
336    /// use overlay_map::OverlayMap;
337    ///
338    /// let mut map = OverlayMap::new();
339    /// map.push("a", 1);
340    ///
341    /// let replaced = map.extend_count([("a", 2), ("b", 3)]);
342    /// assert_eq!(replaced, 1); // "a" was already present, "b" was new
343    ///
344    /// assert_eq!(map.fg(&"a"), Some(&2));
345    /// assert_eq!(map.bg(&"a"), Some(&1));
346    /// assert_eq!(map.fg(&"b"), Some(&3));
347    /// ```
348    pub fn extend_count<I>(&mut self, iter: I) -> usize
349    where
350        I: IntoIterator<Item = (K, V)>,
351    {
352        let mut replaced = 0;
353        for (key, val) in iter {
354            replaced += self.push(key, val) as usize;
355        }
356        replaced
357    }
358}
359
360impl<K, V, S> Clone for OverlayMap<K, V, S>
361where
362    K: Clone + Eq + Hash,
363    V: Clone,
364    S: Clone + BuildHasher,
365{
366    fn clone(&self) -> Self {
367        Self {
368            map: self.map.clone(),
369        }
370    }
371}
372
373impl<K, V, S> PartialEq for OverlayMap<K, V, S>
374where
375    K: Eq + Hash,
376    V: PartialEq,
377    S: BuildHasher,
378{
379    fn eq(&self, other: &Self) -> bool {
380        self.map == other.map
381    }
382}
383
384impl<K, V, S> Eq for OverlayMap<K, V, S>
385where
386    K: Eq + Hash,
387    V: Eq,
388    S: BuildHasher,
389{
390}
391
392impl<K, V, S> Extend<(K, V)> for OverlayMap<K, V, S>
393where
394    K: Eq + Hash,
395    S: BuildHasher + Default,
396{
397    /// Inserts each `(K, V)` pair into the map by pushing the value into the foreground layer.
398    ///
399    /// This behaves the same as calling [`push`] for each element in the iterator. If a key
400    /// already exists, the current foreground value is moved to the background, and the
401    /// new value becomes the foreground. If the key is new, it is inserted.
402    ///
403    /// This implementation does **not** return any count of replaced entries — if you need that,
404    /// use [`extend_count`](Self::extend_count) instead.
405    ///
406    /// # Example
407    /// ```
408    /// use overlay_map::OverlayMap;
409    ///
410    /// let mut map = OverlayMap::new();
411    /// map.extend([("x", 1), ("y", 2)]);
412    ///
413    /// assert_eq!(map.fg(&"x"), Some(&1));
414    /// assert_eq!(map.fg(&"y"), Some(&2));
415    /// ```
416    fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
417        for (k, v) in iter {
418            self.push(k, v);
419        }
420    }
421}
422
423impl<K, V, S> IntoIterator for OverlayMap<K, V, S>
424where
425    K: Eq + Hash,
426    S: BuildHasher,
427{
428    type Item = (K, Overlay<V>);
429    type IntoIter = hashbrown::hash_map::IntoIter<K, Overlay<V>>;
430
431    fn into_iter(self) -> Self::IntoIter {
432        self.map.into_iter()
433    }
434}
435
436const SLOT0_PRESENT: u8 = 1 << 0;
437const SLOT1_PRESENT: u8 = 1 << 1;
438const SLOT_MASK: u8 = SLOT0_PRESENT | SLOT1_PRESENT;
439const FG_SLOT: u8 = 1 << 2;
440
441/// A two-layer value container used by [`OverlayMap`] to manage current and historical values.
442///
443/// `Overlay<T>` stores up to two values:
444///
445/// - A **foreground** value representing the current state.
446/// - An optional **background** value representing the previous state.
447///
448/// When used through [`OverlayMap`], each key maps to an `Overlay<T>` to track updates
449/// without requiring clones or reallocations. You can also use `Overlay<T>` standalone
450/// to manage two-layer state transitions for any value type.
451///
452/// Values are moved, never cloned. All operations (push, pull, swap) are zero-cost and
453/// memory-efficient.
454///
455/// # Use Cases
456///
457/// - Managing current and previous state in UI or simulation logic
458/// - Efficient delta tracking for configs, game state, etc.
459/// - Avoiding `Option<(T, T)>` or custom wrappers with cloning overhead
460///
461/// # Examples
462///
463/// ```
464/// use overlay_map::Overlay;
465///
466/// let mut entry = Overlay::new_fg("current");
467/// entry.push("next"); // moves "current" into background
468///
469/// assert_eq!(entry.fg(), Some(&"next"));
470/// assert_eq!(entry.bg(), Some(&"current"));
471///
472/// let pulled = entry.pull();
473/// assert_eq!(pulled, Some("next"));
474/// assert_eq!(entry.fg(), Some(&"current"));
475/// ```
476#[derive(Debug)]
477pub struct Overlay<T> {
478    bits: u8,
479    slots: [MaybeUninit<T>; 2],
480}
481
482impl<T> Overlay<T> {
483    /// Creates a new `Overlay` with no values.
484    ///
485    /// ```
486    /// use overlay_map::Overlay;
487    ///
488    /// let entry: Overlay<&str> = Overlay::new_empty();
489    /// assert!(entry.is_empty());
490    /// assert_eq!(entry.fg(), None);
491    /// assert_eq!(entry.bg(), None);
492    /// ```
493    pub fn new_empty() -> Self {
494        Self {
495            bits: 0,
496            slots: [MaybeUninit::uninit(), MaybeUninit::uninit()],
497        }
498    }
499
500    /// Creates a new `Overlay` with a foreground value and no background.
501    ///
502    /// ```
503    /// use overlay_map::Overlay;
504    ///
505    /// let entry = Overlay::new_fg("fg");
506    /// assert_eq!(entry.fg(), Some(&"fg"));
507    /// assert_eq!(entry.bg(), None);
508    /// ```
509    pub fn new_fg(val: T) -> Self {
510        Self {
511            bits: SLOT0_PRESENT,
512            slots: [MaybeUninit::new(val), MaybeUninit::uninit()],
513        }
514    }
515
516    /// Creates a new `Overlay` with both foreground and background values.
517    ///
518    /// ```
519    /// use overlay_map::Overlay;
520    ///
521    /// let entry = Overlay::new_both("fg", "bg");
522    /// assert_eq!(entry.fg(), Some(&"fg"));
523    /// assert_eq!(entry.bg(), Some(&"bg"));
524    /// ```
525    pub fn new_both(fg: T, bg: T) -> Self {
526        Self {
527            bits: SLOT0_PRESENT | SLOT1_PRESENT,
528            slots: [MaybeUninit::new(fg), MaybeUninit::new(bg)],
529        }
530    }
531
532    /// Returns a reference to the current foreground value, if present.
533    ///
534    /// This returns `Some(&T)` only if the foreground slot contains a value.
535    /// If the slot is logically empty, returns `None`. This is a safe version that
536    /// checks the presence bits before accessing memory.
537    ///
538    /// # Safety
539    /// This function is fully safe and performs a presence check before dereferencing.
540    ///
541    /// # Returns
542    /// - `Some(&T)` if the foreground slot is initialized
543    /// - `None` if the foreground slot is uninitialized
544    ///
545    /// ```
546    /// use overlay_map::OverlayMap;
547    ///
548    /// let mut map = OverlayMap::new();
549    /// map.push("x", 10);
550    /// map.push("x", 20);
551    /// assert_eq!(map.fg(&"x"), Some(&20));
552    /// assert_eq!(map.bg(&"x"), Some(&10));
553    /// ```
554    #[inline]
555    pub fn fg(&self) -> Option<&T> {
556        let idx = self.fg_index();
557        if self.is_slot_present(idx) {
558            Some(unsafe { self.slots[idx].assume_init_ref() })
559        } else {
560            None
561        }
562    }
563
564    /// Returns a reference to the foreground value **without checking** if it is present.
565    ///
566    /// # Safety
567    /// This function **assumes** the foreground slot is initialized. Calling this when
568    /// the slot is uninitialized (i.e. after a `pull()` without a background, or
569    /// after constructing an empty `Overlay`) results in **undefined behavior**.
570    ///
571    /// Use [`fg`](Self::fg) if you are not certain the slot is populated.
572    ///
573    /// ```
574    /// use overlay_map::Overlay;
575    ///
576    /// let entry = Overlay::new_both("fg", "bg");
577    /// assert_eq!(entry.fg_unchecked(), &"fg");
578    /// assert_eq!(entry.bg_unchecked(), &"bg");
579    /// ```
580    #[inline]
581    pub fn fg_unchecked(&self) -> &T {
582        let idx = self.fg_index();
583        unsafe { self.slots[idx].assume_init_ref() }
584    }
585
586    /// Returns a reference to the background value, if present.
587    ///
588    /// Returns `Some(&T)` only if the background slot is initialized.
589    ///
590    /// ```
591    /// use overlay_map::OverlayMap;
592    ///
593    /// let mut map = OverlayMap::new();
594    /// map.push("x", 10);
595    /// map.push("x", 20);
596    /// assert_eq!(map.fg(&"x"), Some(&20));
597    /// assert_eq!(map.bg(&"x"), Some(&10));
598    /// ```
599    #[inline]
600    pub fn bg(&self) -> Option<&T> {
601        let idx = self.bg_index();
602        if self.is_slot_present(idx) {
603            Some(unsafe { self.slots[idx].assume_init_ref() })
604        } else {
605            None
606        }
607    }
608
609    /// Returns a reference to the background value **without checking** if it is present.
610    ///
611    /// # Safety
612    /// This assumes the background slot is initialized. Calling this when it is not
613    /// will cause **undefined behavior**.
614    ///
615    /// Prefer [`bg`](Self::bg) if you're unsure whether the background is set.
616    ///
617    /// ```
618    /// use overlay_map::Overlay;
619    ///
620    /// let entry = Overlay::new_both("fg", "bg");
621    /// assert_eq!(entry.fg_unchecked(), &"fg");
622    /// assert_eq!(entry.bg_unchecked(), &"bg");
623    /// ```
624    #[inline]
625    pub fn bg_unchecked(&self) -> &T {
626        let idx = self.bg_index();
627        unsafe { self.slots[idx].assume_init_ref() }
628    }
629
630    /// Returns `true` if both slots are empty.
631    ///
632    /// This is used to determine whether the entry contains any values
633    /// at all. It does not consider which slot is foreground or background.
634    ///
635    /// ```
636    /// use overlay_map::Overlay;
637    ///
638    /// let mut entry = Overlay::new_fg("fg");
639    /// assert!(!entry.is_empty());
640    /// entry.pull();
641    /// assert!(entry.is_empty());
642    /// ```
643    #[inline]
644    pub fn is_empty(&self) -> bool {
645        (self.bits & SLOT_MASK) == 0
646    }
647
648    /// Returns `true` if both foreground and background values are currently present.
649    ///
650    /// This is useful for determining whether [`clear_unchecked`](Self::clear_unchecked)
651    /// is safe to call.
652    ///
653    /// # Example
654    /// ```
655    /// use overlay_map::Overlay;
656    ///
657    /// let mut entry = Overlay::new_both("a", "b");
658    /// assert!(entry.is_full());
659    ///
660    /// entry.pull();
661    /// assert!(!entry.is_full()); // background promoted, only one value remains
662    /// ```
663    #[inline]
664    pub fn is_full(&self) -> bool {
665        (self.bits & SLOT_MASK) == SLOT_MASK
666    }
667
668    /// Clears the overlay, dropping any foreground and background values.
669    ///
670    /// This is the most efficient way to reset the overlay to an empty state. It
671    /// avoids value movement or promotion and directly drops the contents of both
672    /// slots (if present). After calling `clear`, the overlay will report as empty,
673    /// and both `fg()` and `bg()` will return `None`.
674    ///
675    /// # Example
676    /// ```
677    /// use overlay_map::Overlay;
678    ///
679    /// let mut entry = Overlay::new_both("a", "b");
680    /// assert_eq!(entry.fg(), Some(&"a"));
681    /// assert_eq!(entry.bg(), Some(&"b"));
682    ///
683    /// entry.clear();
684    ///
685    /// assert_eq!(entry.fg(), None);
686    /// assert_eq!(entry.bg(), None);
687    /// assert!(entry.is_empty());
688    /// ```
689    #[inline]
690    pub fn clear(&mut self) {
691        if (self.bits & SLOT0_PRESENT) != 0 {
692            unsafe { self.slots[0].assume_init_drop() };
693        }
694        if (self.bits & SLOT1_PRESENT) != 0 {
695            unsafe { self.slots[1].assume_init_drop() };
696        }
697        self.bits = 0;
698    }
699
700    /// Clears the overlay without checking which slots are present.
701    ///
702    /// This is an **unsafe**, ultra-fast variant of [`Overlay::clear`] that skips
703    /// all internal presence checks. It will **unconditionally drop** both slots,
704    /// regardless of whether they are actually initialized.
705    ///
706    /// # Safety
707    ///
708    /// You must guarantee that both the **foreground** and **background** values
709    /// are currently present in the overlay. Calling this when either layer is
710    /// missing will result in **undefined behavior**, such as memory corruption
711    /// or double-drop.
712    ///
713    /// This is intended for use in performance-critical contexts where you already
714    /// know the exact slot state — for example, if you've just cloned from a known
715    /// full overlay, or you're clearing a batch of overlays all known to be full.
716    ///
717    /// For a safe version, use [`clear`](Self::clear).
718    ///
719    /// # Example
720    /// ```
721    /// use overlay_map::Overlay;
722    ///
723    /// let mut entry = Overlay::new_both("a", "b");
724    /// entry.clear_unchecked(); // caller guarantees both slots are present
725    ///
726    /// assert!(entry.is_empty());
727    /// ```
728    ///
729    /// # See Also
730    /// - [`Overlay::clear`] — safe version with slot checks
731    /// - [`Overlay::is_empty`] — to check for emptiness before clearing
732    #[inline]
733    pub fn clear_unchecked(&mut self) {
734        unsafe {
735            self.slots[0].assume_init_drop();
736            self.slots[1].assume_init_drop();
737        }
738        self.bits = 0;
739    }
740
741    /// Push a value into the foreground layer, preserving the previous foreground in the background.
742    ///
743    /// If the foreground slot already contains a value, it is moved into the background slot.
744    /// The new value is then written into the foreground slot. Any previous background value
745    /// will be dropped to make room—no cloning is performed at any point.
746    ///
747    /// This operation is always safe, even if the entry is empty. If no foreground is currently
748    /// present, the value will simply be inserted.
749    ///
750    /// # Example
751    /// ```
752    /// use overlay_map::Overlay;
753    ///
754    /// let mut entry = Overlay::new_fg("a");
755    /// entry.push("b");
756    ///
757    /// assert_eq!(entry.fg(), Some(&"b"));
758    /// assert_eq!(entry.bg(), Some(&"a"));
759    /// ```
760    #[inline]
761    pub fn push(&mut self, val: T) {
762        self.push_fg_to_bg();
763        let idx = self.fg_index();
764        self.slots[idx] = MaybeUninit::new(val);
765        self.bits |= 1 << idx;
766    }
767
768    /// Safely pull the current foreground value out, promoting the background to foreground if present.
769    ///
770    /// If the foreground value is present, it is removed and returned. The background (if any) is
771    /// promoted to the foreground. If neither value remains, the entry becomes empty.
772    ///
773    /// Returns `None` if the foreground was not present.
774    ///
775    /// # Example
776    /// ```
777    /// use overlay_map::Overlay;
778    ///
779    /// let mut entry = Overlay::new_both("a", "b");
780    /// let pulled = entry.pull();
781    ///
782    /// assert_eq!(pulled, Some("a"));
783    /// assert_eq!(entry.fg(), Some(&"b")); // background promoted
784    /// ```
785    #[inline]
786    pub fn pull(&mut self) -> Option<T> {
787        let fgi = self.fg_index();
788        if !self.is_slot_present(fgi) {
789            return None;
790        }
791
792        let evicted = unsafe { self.slots[fgi].assume_init_read() };
793        self.bits &= !(1 << fgi);
794        self.flip();
795        Some(evicted)
796    }
797
798    /// Pull the current foreground value without checking if it is present.
799    ///
800    /// # Safety
801    /// The caller must ensure the foreground slot is present. If it is not, this will result
802    /// in undefined behavior.
803    ///
804    /// See [`Self::pull`] for a safe alternative.
805    ///
806    /// ```
807    /// use overlay_map::Overlay;
808    ///
809    /// let mut entry = Overlay::new_both("fg", "bg");
810    /// let pulled = entry.pull_unchecked();
811    /// assert_eq!(pulled, "fg");
812    /// assert_eq!(entry.fg(), Some(&"bg"));
813    /// ```
814    #[inline]
815    pub fn pull_unchecked(&mut self) -> T {
816        let fgi = self.fg_index();
817        let evicted = unsafe { self.slots[fgi].assume_init_read() };
818        self.bits &= !(1 << fgi);
819        self.flip();
820        evicted
821    }
822
823    /// Swap in a new foreground value, returning the old background if present.
824    ///
825    /// If a background value exists, it is evicted and returned. The new value is written into
826    /// the background slot, which is then promoted to become the new foreground. The current
827    /// foreground is preserved in-place.
828    ///
829    /// If no background was present, this behaves like a standard push operation,
830    /// and `None` is returned.
831    ///
832    /// # Example
833    /// ```
834    /// use overlay_map::Overlay;
835    ///
836    /// let mut entry = Overlay::new_both("a", "b");
837    /// let evicted = entry.swap("c");
838    ///
839    /// assert_eq!(evicted, Some("b"));
840    /// assert_eq!(entry.fg(), Some(&"c"));
841    /// assert_eq!(entry.bg(), Some(&"a"));
842    /// ```
843    #[inline]
844    pub fn swap(&mut self, val: T) -> Option<T> {
845        let bgi = self.bg_index();
846        if self.is_slot_present(bgi) {
847            let evicted = unsafe { self.slots[bgi].assume_init_read() };
848            self.slots[bgi] = MaybeUninit::new(val);
849            self.flip();
850            Some(evicted)
851        } else {
852            self.push(val);
853            None
854        }
855    }
856
857    /// Get an iterator over the foreground and background values.
858    ///
859    /// ```
860    /// use overlay_map::Overlay;
861    ///
862    /// let entry = Overlay::new_both("fg", "bg");
863    /// let values: Vec<_> = entry.iter().cloned().collect();
864    /// assert_eq!(values, vec!["fg", "bg"]);
865    /// ```
866    pub fn iter(&self) -> impl Iterator<Item = &T> {
867        self.fg().into_iter().chain(self.bg())
868    }
869
870    /// Flips the foreground and background layers.
871    ///
872    /// This operation swaps the logical roles of the two slots:
873    ///
874    /// - The foreground becomes the background
875    /// - The background becomes the foreground
876    ///
877    /// This does **not** move or clone any values. It simply toggles an internal
878    /// bit to reinterpret which slot is considered "foreground" and which is "background".
879    ///
880    /// # Example
881    /// ```
882    /// use overlay_map::Overlay;
883    ///
884    /// let mut entry = Overlay::new_both("a", "b");
885    /// assert_eq!(entry.fg(), Some(&"a"));
886    /// assert_eq!(entry.bg(), Some(&"b"));
887    ///
888    /// entry.flip();
889    ///
890    /// assert_eq!(entry.fg(), Some(&"b"));
891    /// assert_eq!(entry.bg(), Some(&"a"));
892    /// ```
893    #[inline]
894    pub fn flip(&mut self) {
895        self.bits ^= FG_SLOT;
896    }
897
898    #[inline]
899    fn fg_index(&self) -> usize {
900        ((self.bits & FG_SLOT) >> 2) as usize
901    }
902
903    #[inline]
904    fn bg_index(&self) -> usize {
905        self.fg_index() ^ 1
906    }
907
908    #[inline]
909    fn is_slot_present(&self, idx: usize) -> bool {
910        (self.bits & (1 << idx)) != 0
911    }
912
913    /// Moves the current foreground value to the background slot, dropping any
914    /// previous background.
915    ///
916    /// This operation updates only internal bits and memory slots. The value
917    /// itself is not cloned or moved in memory. If a background value already
918    /// exists, it is dropped before being replaced.
919    #[inline]
920    fn push_fg_to_bg(&mut self) {
921        let bgi = self.bg_index();
922        if self.is_slot_present(bgi) {
923            unsafe {
924                self.slots[bgi].assume_init_drop();
925            }
926        }
927        self.flip();
928    }
929}
930
931impl<T> Default for Overlay<T> {
932    fn default() -> Self {
933        Self::new_empty()
934    }
935}
936
937impl<T> From<T> for Overlay<T> {
938    fn from(value: T) -> Self {
939        Self::new_fg(value)
940    }
941}
942
943impl<T: Clone> Clone for Overlay<T> {
944    fn clone(&self) -> Self {
945        let mut clone = Self::new_empty();
946        clone.bits = self.bits;
947
948        if self.is_slot_present(0) {
949            clone.slots[0] = MaybeUninit::new(unsafe { self.slots[0].assume_init_ref().clone() });
950        }
951
952        if self.is_slot_present(1) {
953            clone.slots[1] = MaybeUninit::new(unsafe { self.slots[1].assume_init_ref().clone() });
954        }
955
956        clone
957    }
958}
959
960impl<T: PartialEq> PartialEq for Overlay<T> {
961    fn eq(&self, other: &Self) -> bool {
962        if (self.bits & SLOT_MASK) != (other.bits & SLOT_MASK) {
963            return false;
964        }
965        self.fg() == other.fg() && self.bg() == other.bg()
966    }
967}
968
969impl<T: Eq> Eq for Overlay<T> {}
970
971impl<V> Drop for Overlay<V> {
972    fn drop(&mut self) {
973        if (self.bits & SLOT0_PRESENT) != 0 {
974            unsafe { self.slots[0].assume_init_drop() };
975        }
976
977        if (self.bits & SLOT1_PRESENT) != 0 {
978            unsafe { self.slots[1].assume_init_drop() };
979        }
980    }
981}
982
983pub struct OverlayIntoIter<T> {
984    overlay: Overlay<T>,
985}
986
987impl<T> Iterator for OverlayIntoIter<T> {
988    type Item = T;
989
990    fn next(&mut self) -> Option<Self::Item> {
991        self.overlay.pull()
992    }
993}
994
995impl<T> IntoIterator for Overlay<T> {
996    type Item = T;
997    type IntoIter = OverlayIntoIter<T>;
998
999    /// Creates an iterator over the values in the overlay.
1000    ///
1001    /// ```
1002    /// use overlay_map::Overlay;
1003    ///
1004    /// let entry = Overlay::new_both("fg", "bg");
1005    /// let values: Vec<_> = entry.into_iter().collect();
1006    /// assert_eq!(values, vec!["fg", "bg"]);
1007    /// ```
1008    fn into_iter(self) -> Self::IntoIter {
1009        OverlayIntoIter { overlay: self }
1010    }
1011}
1012
1013#[cfg(test)]
1014mod tests {
1015    use super::*;
1016
1017    #[test]
1018    fn push_and_get_foreground() {
1019        let mut map = OverlayMap::<&str, i32>::new();
1020        assert!(map.fg(&"key").is_none());
1021        map.push("key", 42);
1022        assert_eq!(*map.fg(&"key").expect("Entry was just pushed"), 42);
1023    }
1024
1025    #[test]
1026    fn push_and_get_background() {
1027        let mut map = OverlayMap::<&str, i32>::new();
1028        assert!(map.fg(&"key").is_none());
1029        map.push("key", 99);
1030        assert_eq!(*map.fg(&"key").expect("Entry was just pushed"), 99);
1031    }
1032
1033    #[test]
1034    fn push_if_no_change_foreground() {
1035        let mut map = OverlayMap::<&str, i32>::new();
1036        map.push("key", 100);
1037
1038        // Try swap but do nothing
1039        map.push_if(&"key", |old| {
1040            if *old == 100 {
1041                None // no change
1042            } else {
1043                Some(999)
1044            }
1045        });
1046
1047        // Still foreground = 100, no background
1048        assert_eq!(*map.fg(&"key").expect("Entry should still exist"), 100);
1049    }
1050
1051    #[test]
1052    fn push_if_foreground_to_background() {
1053        let mut map = OverlayMap::<&str, i32>::new();
1054        map.push("key", 50);
1055        map.push_if(&"key", |old| if *old == 50 { Some(123) } else { None });
1056        assert_eq!(*map.fg(&"key").expect("Entry should still exist"), 123);
1057        assert_eq!(
1058            *map.bg(&"key").expect("Old value not found in background"),
1059            50
1060        );
1061    }
1062
1063    #[test]
1064    fn push_if_missing_key() {
1065        let mut map = OverlayMap::<&str, i32>::new();
1066        map.push_if(&"missing", |_| Some(999));
1067        assert!(map.fg(&"missing").is_none());
1068    }
1069
1070    #[test]
1071    fn pull_with_remainder_test() {
1072        let mut map = OverlayMap::<&str, i32>::new();
1073        map.push("key", 42);
1074        map.push("key", 24);
1075        assert_eq!(Some(&24), map.fg(&"key"));
1076        assert_eq!(Some(&42), map.bg(&"key"));
1077        assert_eq!(Some(24), map.pull(&"key"));
1078        assert_eq!(Some(&42), map.fg(&"key"));
1079        assert_eq!(None, map.bg(&"key"));
1080        assert_eq!(1, map.len());
1081    }
1082
1083    #[test]
1084    fn pull_without_remainder_test() {
1085        let mut map = OverlayMap::<&str, i32>::new();
1086        map.push("key", 42);
1087        assert_eq!(Some(&42), map.fg(&"key"));
1088        assert_eq!(Some(42), map.pull(&"key"));
1089        assert_eq!(None, map.fg(&"key"));
1090        assert_eq!(None, map.bg(&"key"));
1091        assert_eq!(0, map.len());
1092    }
1093
1094    #[test]
1095    fn swap_test() {
1096        let mut map = OverlayMap::<&str, i32>::new();
1097        map.push("key", 42);
1098        assert_eq!(*map.fg(&"key").expect("Entry was just pushed"), 42);
1099        assert_eq!(None, map.swap("key", 100));
1100        let old_value = map.swap("key", 150);
1101        assert_eq!(old_value, Some(42));
1102        assert_eq!(*map.fg(&"key").expect("Entry was just pushed"), 150);
1103        assert_eq!(*map.bg(&"key").expect("Entry was just pushed"), 100);
1104    }
1105
1106    #[test]
1107    fn swap_if_test() {
1108        let mut map = OverlayMap::<&str, i32>::new();
1109        map.push("key", 50);
1110        map.push("key", 100);
1111        let evicted = map.swap_if(&"key", |old| if *old == 100 { Some(123) } else { None });
1112        assert_eq!(*map.fg(&"key").expect("Entry should still exist"), 123);
1113        assert_eq!(*map.bg(&"key").expect("Entry should still exist"), 100);
1114        assert_eq!(evicted, Some(50));
1115    }
1116
1117    #[test]
1118    fn overlay_test() {
1119        // Initialize an OverlayMap with:
1120        // - "fg_key" in foreground
1121        // - "bg_key" in background
1122        // - "absent_key" absent
1123        let mut map = OverlayMap::<&str, i32>::new();
1124        map.push("fg_key", 10);
1125        map.push("bg_key", 20);
1126
1127        // Prepare updates:
1128        // - "fg_key" -> 100
1129        // - "bg_key" -> 200
1130        // - "none_key" -> 300 (was absent in map)
1131        let updates = vec![("fg_key", 100), ("bg_key", 200), ("none_key", 300)];
1132
1133        // Perform the merge
1134        map.extend_count(updates);
1135
1136        // Check that "fg_key" was in foreground, so old value (10) moved to background.
1137        // New value (100) should be in foreground.
1138        match map.fg(&"fg_key") {
1139            Some(val) => assert_eq!(*val, 100),
1140            _ => panic!("Expected 'fg_key' = 100 in foreground"),
1141        }
1142        match map.bg(&"fg_key") {
1143            Some(val) => assert_eq!(*val, 10),
1144            None => panic!("Expected old 'fg_key' value = 10 in background"),
1145        }
1146
1147        // Check that "none_key" was absent, so it is now in the foreground with 300
1148        match map.fg(&"none_key") {
1149            Some(val) => assert_eq!(*val, 300),
1150            _ => panic!("Expected 'none_key' = 300 in foreground"),
1151        }
1152        // It shouldn't exist in background
1153        assert!(map.bg(&"none_key").is_none());
1154    }
1155}