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}