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 self.bits ^= FG_SLOT | (1 << fgi);
870 Some(unsafe { self.slots[fgi].assume_init_read() })
871 } else {
872 None
873 }
874 }
875
876 /// Pull the current foreground value without checking if it is present.
877 ///
878 /// # Safety
879 /// The caller must ensure the foreground slot is present. If it is not, this will result
880 /// in undefined behavior.
881 ///
882 /// See [`Self::pull`] for a safe alternative.
883 ///
884 /// ```
885 /// use overlay_map::Overlay;
886 ///
887 /// let mut entry = Overlay::new_both("fg", "bg");
888 /// let pulled = entry.pull_unchecked();
889 /// assert_eq!(pulled, "fg");
890 /// assert_eq!(entry.fg(), Some(&"bg"));
891 /// ```
892 #[inline]
893 pub fn pull_unchecked(&mut self) -> T {
894 let fgi = self.fg_index();
895 self.bits ^= FG_SLOT | (1 << fgi);
896 unsafe { self.slots[fgi].assume_init_read() }
897 }
898
899 /// Swap in a new foreground value, returning the old background if present.
900 ///
901 /// If a background value exists, it is evicted and returned. The new value is written into
902 /// the background slot, which is then promoted to become the new foreground. The current
903 /// foreground is preserved in-place.
904 ///
905 /// If no background was present, this behaves like a standard push operation,
906 /// and `None` is returned.
907 ///
908 /// # Example
909 /// ```
910 /// use overlay_map::Overlay;
911 ///
912 /// let mut entry = Overlay::new_both("a", "b");
913 /// let evicted = entry.swap("c");
914 ///
915 /// assert_eq!(evicted, Some("b"));
916 /// assert_eq!(entry.fg(), Some(&"c"));
917 /// assert_eq!(entry.bg(), Some(&"a"));
918 /// ```
919 #[inline]
920 pub fn swap(&mut self, val: T) -> Option<T> {
921 let bgi = self.bg_index();
922 if self.is_slot_present(bgi) {
923 let evicted = unsafe { self.slots[bgi].assume_init_read() };
924 self.slots[bgi] = MaybeUninit::new(val);
925 self.flip_unchecked();
926 Some(evicted)
927 } else {
928 self.push(val);
929 None
930 }
931 }
932
933 /// Get an iterator over the foreground and background values.
934 ///
935 /// ```
936 /// use overlay_map::Overlay;
937 ///
938 /// let entry = Overlay::new_both("fg", "bg");
939 /// let values: Vec<_> = entry.iter().cloned().collect();
940 /// assert_eq!(values, vec!["fg", "bg"]);
941 /// ```
942 pub fn iter(&self) -> impl Iterator<Item = &T> {
943 self.fg().into_iter().chain(self.bg())
944 }
945
946 /// Flips the foreground and background layers, if both are present.
947 ///
948 /// This operation swaps the logical roles of the two slots:
949 ///
950 /// - The foreground becomes the background
951 /// - The background becomes the foreground
952 ///
953 /// If only one value is present, the overlay remains unchanged to preserve
954 /// the guarantee that a foreground value is always present when the overlay is in use.
955 ///
956 /// This is a zero-cost, branchless operation — no memory is moved, cloned, or reallocated.
957 /// Internally, it simply toggles a bit flag **only if** both slots are occupied.
958 ///
959 /// # Example
960 /// ```
961 /// use overlay_map::Overlay;
962 ///
963 /// let mut entry = Overlay::new_both("a", "b");
964 /// assert_eq!(entry.fg(), Some(&"a"));
965 /// assert_eq!(entry.bg(), Some(&"b"));
966 ///
967 /// entry.flip();
968 ///
969 /// assert_eq!(entry.fg(), Some(&"b"));
970 /// assert_eq!(entry.bg(), Some(&"a"));
971 ///
972 /// // Flip has no effect when only one value is present
973 /// let mut single = Overlay::new_fg("only");
974 /// single.flip();
975 /// assert_eq!(single.fg(), Some(&"only"));
976 /// assert_eq!(single.bg(), None);
977 /// ```
978 #[inline]
979 pub fn flip(&mut self) {
980 if (self.bits & SLOT_MASK) == SLOT_MASK {
981 self.bits ^= FG_SLOT;
982 }
983 }
984
985 /// Flips the foreground and background slots **without checking** if both are present.
986 ///
987 /// This is the unchecked, zero-cost variant of [`flip`](Self::flip), intended for internal
988 /// or performance-critical use when it is already known that both slots contain valid values.
989 ///
990 /// This method **does not perform any presence checks**. If one of the slots is uninitialized,
991 /// calling this method results in **undefined behavior** when those slots are later accessed.
992 ///
993 /// # Safety
994 ///
995 /// The caller must guarantee that:
996 ///
997 /// - Both slots (foreground and background) are currently initialized.
998 /// - A subsequent use of `fg_unchecked` or `bg_unchecked` will not access uninitialized memory.
999 ///
1000 /// # Example
1001 /// ```
1002 /// use overlay_map::Overlay;
1003 ///
1004 /// let mut entry = Overlay::new_both("a", "b");
1005 /// entry.flip_unchecked(); // swaps roles without checks
1006 /// assert_eq!(entry.fg(), Some(&"b"));
1007 /// assert_eq!(entry.bg(), Some(&"a"));
1008 /// ```
1009 #[inline]
1010 pub fn flip_unchecked(&mut self) {
1011 self.bits ^= FG_SLOT;
1012 }
1013
1014 #[inline]
1015 fn fg_index(&self) -> usize {
1016 ((self.bits & FG_SLOT) >> 2) as usize
1017 }
1018
1019 #[inline]
1020 fn bg_index(&self) -> usize {
1021 self.fg_index() ^ 1
1022 }
1023
1024 #[inline]
1025 fn is_slot_present(&self, idx: usize) -> bool {
1026 (self.bits & (1 << idx)) != 0
1027 }
1028
1029 /// Moves the current foreground value to the background slot, dropping any
1030 /// previous background.
1031 ///
1032 /// This operation updates only internal bits and memory slots. The value
1033 /// itself is not cloned or moved in memory. If a background value already
1034 /// exists, it is dropped before being replaced.
1035 #[inline]
1036 fn push_fg_to_bg(&mut self) {
1037 let bgi = self.bg_index();
1038 if self.is_slot_present(bgi) {
1039 unsafe {
1040 self.slots[bgi].assume_init_drop();
1041 }
1042 }
1043 self.flip_unchecked();
1044 }
1045}
1046
1047impl<T> Default for Overlay<T> {
1048 fn default() -> Self {
1049 Self::new_empty()
1050 }
1051}
1052
1053impl<T> From<T> for Overlay<T> {
1054 fn from(value: T) -> Self {
1055 Self::new_fg(value)
1056 }
1057}
1058
1059impl<T: Clone> Clone for Overlay<T> {
1060 fn clone(&self) -> Self {
1061 let mut clone = Self::new_empty();
1062 clone.bits = self.bits;
1063
1064 if self.is_slot_present(0) {
1065 clone.slots[0] = MaybeUninit::new(unsafe { self.slots[0].assume_init_ref().clone() });
1066 }
1067
1068 if self.is_slot_present(1) {
1069 clone.slots[1] = MaybeUninit::new(unsafe { self.slots[1].assume_init_ref().clone() });
1070 }
1071
1072 clone
1073 }
1074}
1075
1076impl<T: PartialEq> PartialEq for Overlay<T> {
1077 fn eq(&self, other: &Self) -> bool {
1078 if (self.bits & SLOT_MASK) != (other.bits & SLOT_MASK) {
1079 return false;
1080 }
1081 self.fg() == other.fg() && self.bg() == other.bg()
1082 }
1083}
1084
1085impl<T: Eq> Eq for Overlay<T> {}
1086
1087impl<V> Drop for Overlay<V> {
1088 fn drop(&mut self) {
1089 if (self.bits & SLOT0_PRESENT) != 0 {
1090 unsafe { self.slots[0].assume_init_drop() };
1091 }
1092
1093 if (self.bits & SLOT1_PRESENT) != 0 {
1094 unsafe { self.slots[1].assume_init_drop() };
1095 }
1096 }
1097}
1098
1099pub struct OverlayIntoIter<T> {
1100 overlay: Overlay<T>,
1101}
1102
1103impl<T> Iterator for OverlayIntoIter<T> {
1104 type Item = T;
1105
1106 fn next(&mut self) -> Option<Self::Item> {
1107 self.overlay.pull()
1108 }
1109}
1110
1111impl<T> IntoIterator for Overlay<T> {
1112 type Item = T;
1113 type IntoIter = OverlayIntoIter<T>;
1114
1115 /// Creates an iterator over the values in the overlay.
1116 ///
1117 /// ```
1118 /// use overlay_map::Overlay;
1119 ///
1120 /// let entry = Overlay::new_both("fg", "bg");
1121 /// let values: Vec<_> = entry.into_iter().collect();
1122 /// assert_eq!(values, vec!["fg", "bg"]);
1123 /// ```
1124 fn into_iter(self) -> Self::IntoIter {
1125 OverlayIntoIter { overlay: self }
1126 }
1127}
1128
1129#[cfg(test)]
1130mod tests {
1131 use super::*;
1132
1133 #[test]
1134 fn integration_push_pull_cycle() {
1135 let mut map = OverlayMap::<&str, i32>::new();
1136
1137 map.push("x", 1);
1138 map.push("x", 2);
1139 map.push("x", 3);
1140
1141 assert_eq!(map.fg(&"x"), Some(&3));
1142 assert_eq!(map.bg(&"x"), Some(&2));
1143
1144 let pulled = map.pull(&"x");
1145 assert_eq!(pulled, Some(3));
1146 assert_eq!(map.fg(&"x"), Some(&2));
1147
1148 let pulled = map.pull(&"x");
1149 assert_eq!(pulled, Some(2));
1150 assert_eq!(map.fg(&"x"), None);
1151 assert!(map.is_empty());
1152 }
1153
1154 #[test]
1155 fn extend_count_overlapping_and_new() {
1156 let mut map = OverlayMap::<&str, i32>::new();
1157 map.push("a", 10);
1158 map.push("b", 20);
1159
1160 let replaced = map.extend_count([("a", 100), ("c", 300), ("b", 200)]);
1161 assert_eq!(replaced, 2); // a and b existed
1162
1163 assert_eq!(map.fg(&"a"), Some(&100));
1164 assert_eq!(map.bg(&"a"), Some(&10));
1165
1166 assert_eq!(map.fg(&"b"), Some(&200));
1167 assert_eq!(map.bg(&"b"), Some(&20));
1168
1169 assert_eq!(map.fg(&"c"), Some(&300));
1170 assert_eq!(map.bg(&"c"), None);
1171 }
1172
1173 #[test]
1174 fn push_if_and_swap_if_logic() {
1175 let mut map = OverlayMap::<&str, i32>::new();
1176 map.push("key", 1);
1177
1178 let pushed = map.push_if(&"key", |v| if *v < 5 { Some(*v + 10) } else { None });
1179 assert!(pushed);
1180 assert_eq!(map.fg(&"key"), Some(&11));
1181 assert_eq!(map.bg(&"key"), Some(&1));
1182
1183 let evicted = map.swap_if(&"key", |v| if *v == 11 { Some(42) } else { None });
1184 assert_eq!(evicted, Some(1));
1185 assert_eq!(map.fg(&"key"), Some(&42));
1186 assert_eq!(map.bg(&"key"), Some(&11));
1187 }
1188}