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