Skip to main content

zrx_store/
stash.rs

1// Copyright (c) 2025-2026 Zensical and contributors
2
3// SPDX-License-Identifier: MIT
4// All contributions are certified under the DCO
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to
8// deal in the Software without restriction, including without limitation the
9// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10// sell copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22// IN THE SOFTWARE.
23
24// ----------------------------------------------------------------------------
25
26//! Stash.
27
28use ahash::HashMap;
29use slab::Slab;
30use std::borrow::Borrow;
31use std::fmt::{self, Debug};
32use std::marker::PhantomData;
33use std::mem;
34use std::ops::{Index, IndexMut};
35
36use crate::store::adapter::slab::{Iter, IterMut};
37use crate::store::item::{Key, Value};
38use crate::store::{
39    Store, StoreIterable, StoreIterableMut, StoreMut, StoreMutRef,
40};
41
42pub mod items;
43mod iter;
44
45pub use items::Items;
46pub use iter::{Slots, SlotsMut};
47
48// ----------------------------------------------------------------------------
49// Implementations
50// ----------------------------------------------------------------------------
51
52/// Stash.
53///
54/// This data type implements a simple stash, which is a key-value store that
55/// is optimized for fast insertion and retrieval of items by index. It's built
56/// on a [`Slab`], together with a [`Store`] that provides the underlying item
57/// storage. Stashes offer optimal performance for temporary storage.
58///
59/// Iteration happens on the underlying [`Slab`], which means that the order of
60/// items is stable, but not sorted by key. This ensures, that iteration is not
61/// affected by insertions and removals, and cache efficient, since no lookups
62/// need to be performed on the underlying [`Store`] to obtain the items. Note
63/// that the store iterator traits don't allow to return indices for the items,
64/// only references to keys and values. In case indices are required, the stash
65/// can be iterated with [`Stash::slots`] or [`Stash::slots_mut`], since those
66/// return both, indices and references to keys and values.
67///
68/// # Examples
69///
70/// ```
71/// use zrx_store::{Stash, StoreMut};
72///
73/// // Create stash and initial state
74/// let mut stash = Stash::default();
75/// stash.insert("key", 42);
76///
77/// // Create iterator over the stash
78/// for (key, value) in &stash {
79///     println!("{key}: {value}");
80/// }
81/// ```
82#[derive(Clone)]
83pub struct Stash<K, V, S = HashMap<K, usize>> {
84    /// Underlying store.
85    store: S,
86    /// Stash items.
87    items: Slab<(K, V)>,
88    /// Capture types.
89    marker: PhantomData<K>,
90}
91
92// ----------------------------------------------------------------------------
93// Implementations
94// ----------------------------------------------------------------------------
95
96impl<K, V, S> Stash<K, V, S>
97where
98    K: Key,
99    S: Store<K, usize>,
100{
101    /// Creates a stash.
102    ///
103    /// # Examples
104    ///
105    /// ```
106    /// use std::collections::HashMap;
107    /// use zrx_store::Stash;
108    ///
109    /// // Create stash
110    /// let mut stash = Stash::<_, _, HashMap<_, _>>::new();
111    /// stash.insert("key", 42);
112    /// ```
113    #[must_use]
114    pub fn new() -> Self
115    where
116        S: Default,
117    {
118        Self {
119            store: S::default(),
120            items: Slab::new(),
121            marker: PhantomData,
122        }
123    }
124
125    /// Returns the index of the value identified by the key.
126    ///
127    /// # Examples
128    ///
129    /// ```
130    /// use zrx_store::Stash;
131    ///
132    /// // Create stash and initial state
133    /// let mut stash = Stash::default();
134    /// stash.insert("key", 42);
135    ///
136    /// // Obtain index of value
137    /// let index = stash.get(&"key");
138    /// assert_eq!(index, Some(0));
139    /// ```
140    #[inline]
141    pub fn get<Q>(&self, key: &Q) -> Option<usize>
142    where
143        K: Borrow<Q>,
144        Q: Key,
145    {
146        self.store.get(key).copied()
147    }
148
149    /// Returns a reference to the key at the index.
150    ///
151    /// # Examples
152    ///
153    /// ```
154    /// use zrx_store::Stash;
155    ///
156    /// // Create stash and initial state
157    /// let mut stash = Stash::default();
158    /// stash.insert("key", 42);
159    ///
160    /// // Obtain key at index
161    /// let key = stash.key(0);
162    /// assert_eq!(key, Some(&"key"));
163    /// ```
164    #[inline]
165    pub fn key(&self, index: usize) -> Option<&K> {
166        self.items.get(index).map(|(key, _)| key)
167    }
168}
169
170impl<K, V, S> Stash<K, V, S>
171where
172    K: Key,
173    S: StoreMut<K, usize>,
174{
175    /// Inserts the value identified by the key and returns its index.
176    ///
177    /// This method inserts the value and returns an index into the store that
178    /// can be used to retrieve an immutable or mutable reference to the value.
179    ///
180    /// # Examples
181    ///
182    /// ```
183    /// use zrx_store::Stash;
184    ///
185    /// // Create stash
186    /// let mut stash = Stash::default();
187    ///
188    /// // Insert value
189    /// let index = stash.insert("key", 42);
190    /// assert_eq!(index, 0);
191    /// ```
192    #[inline]
193    pub fn insert(&mut self, key: K, value: V) -> usize {
194        if let Some(&index) = self.store.get(&key) {
195            self.items[index].1 = value;
196            index
197        } else {
198            let index = self.items.insert((key.clone(), value));
199            self.store.insert(key, index);
200            index
201        }
202    }
203
204    /// Removes the entry at the index and returns it.
205    ///
206    /// # Examples
207    ///
208    /// ```
209    /// use zrx_store::Stash;
210    ///
211    /// // Create stash and initial state
212    /// let mut stash = Stash::default();
213    /// stash.insert("key", 42);
214    ///
215    /// // Remove and return entry
216    /// let entry = stash.remove(0);
217    /// assert_eq!(entry, Some(("key", 42)));
218    /// ```
219    #[inline]
220    pub fn remove(&mut self, index: usize) -> Option<(K, V)> {
221        if let Some((key, _)) = self.items.get(index) {
222            self.store.remove(key).map(|index| self.items.remove(index))
223        } else {
224            None
225        }
226    }
227}
228
229// ----------------------------------------------------------------------------
230// Trait implementations
231// ----------------------------------------------------------------------------
232
233impl<K, V, S> Store<K, V> for Stash<K, V, S>
234where
235    K: Key,
236    S: Store<K, usize>,
237{
238    /// Returns a reference to the value identified by the key.
239    ///
240    /// # Examples
241    ///
242    /// ```
243    /// use zrx_store::{Stash, Store};
244    ///
245    /// // Create stash and initial state
246    /// let mut stash = Stash::default();
247    /// stash.insert("key", 42);
248    ///
249    /// // Obtain reference to value
250    /// let value = Store::get(&stash, &"key");
251    /// assert_eq!(value, Some(&42));
252    /// ```
253    #[inline]
254    fn get<Q>(&self, key: &Q) -> Option<&V>
255    where
256        K: Borrow<Q>,
257        Q: Key,
258    {
259        match self.store.get(key) {
260            Some(&index) => self.items.get(index).map(|(_, value)| value),
261            None => None,
262        }
263    }
264
265    /// Returns whether the store contains the key.
266    ///
267    /// # Examples
268    ///
269    /// ```
270    /// use zrx_store::{Stash, Store};
271    ///
272    /// // Create stash and initial state
273    /// let mut stash = Stash::default();
274    /// stash.insert("key", 42);
275    ///
276    /// // Ensure presence of key
277    /// let check = stash.contains_key(&"key");
278    /// assert_eq!(check, true);
279    /// ```
280    #[inline]
281    fn contains_key<Q>(&self, key: &Q) -> bool
282    where
283        K: Borrow<Q>,
284        Q: Key,
285    {
286        self.store.contains_key(key)
287    }
288
289    /// Returns the number of items in the store.
290    #[inline]
291    fn len(&self) -> usize {
292        self.store.len()
293    }
294}
295
296impl<K, V, S> StoreMut<K, V> for Stash<K, V, S>
297where
298    K: Key,
299    V: Value,
300    S: StoreMut<K, usize>,
301{
302    /// Inserts the value identified by the key.
303    ///
304    /// # Examples
305    ///
306    /// ```
307    /// use zrx_store::{Stash, StoreMut};
308    ///
309    /// // Create stash
310    /// let mut stash = Stash::default();
311    ///
312    /// // Insert value
313    /// let value = StoreMut::insert(&mut stash, "key", 42);
314    /// assert_eq!(value, None);
315    /// ```
316    #[inline]
317    fn insert(&mut self, key: K, value: V) -> Option<V> {
318        if let Some(&index) = self.store.get(&key) {
319            let prior = &mut self.items[index].1;
320            (prior != &value).then(|| mem::replace(prior, value))
321        } else {
322            let index = self.items.insert((key.clone(), value));
323            self.store.insert(key, index);
324            None
325        }
326    }
327
328    /// Removes the value identified by the key.
329    ///
330    /// # Examples
331    ///
332    /// ```
333    /// use zrx_store::{Stash, StoreMut};
334    ///
335    /// // Create stash and initial state
336    /// let mut stash = Stash::default();
337    /// stash.insert("key", 42);
338    ///
339    /// // Remove and return value
340    /// let value = StoreMut::remove(&mut stash, &"key");
341    /// assert_eq!(value, Some(42));
342    /// ```
343    #[inline]
344    fn remove<Q>(&mut self, key: &Q) -> Option<V>
345    where
346        K: Borrow<Q>,
347        Q: Key,
348    {
349        self.store.remove(key).map(|index| {
350            let (_, value) = self.items.remove(index);
351            value
352        })
353    }
354
355    /// Removes the value identified by the key and returns both.
356    ///
357    /// # Examples
358    ///
359    /// ```
360    /// use zrx_store::{Stash, StoreMut};
361    ///
362    /// // Create stash and initial state
363    /// let mut stash = Stash::default();
364    /// stash.insert("key", 42);
365    ///
366    /// // Remove and return entry
367    /// let entry = stash.remove_entry(&"key");
368    /// assert_eq!(entry, Some(("key", 42)));
369    /// ```
370    #[inline]
371    fn remove_entry<Q>(&mut self, key: &Q) -> Option<(K, V)>
372    where
373        K: Borrow<Q>,
374        Q: Key,
375    {
376        self.store.remove(key).map(|index| self.items.remove(index))
377    }
378
379    /// Clears the stash, removing all items.
380    ///
381    /// # Examples
382    ///
383    /// ```
384    /// use zrx_store::{Stash, Store, StoreMut};
385    ///
386    /// // Create stash and initial state
387    /// let mut stash = Stash::default();
388    /// stash.insert("key", 42);
389    ///
390    /// // Clear stash
391    /// stash.clear();
392    /// assert!(stash.is_empty());
393    /// ```
394    #[inline]
395    fn clear(&mut self) {
396        self.store.clear();
397        self.items.clear();
398    }
399}
400
401impl<K, V, S> StoreMutRef<K, V> for Stash<K, V, S>
402where
403    K: Key,
404    S: StoreMut<K, usize>,
405{
406    /// Returns a mutable reference to the value identified by the key.
407    ///
408    /// # Examples
409    ///
410    /// ```
411    /// use zrx_store::{Stash, StoreMut, StoreMutRef};
412    ///
413    /// // Create stash and initial state
414    /// let mut stash = Stash::default();
415    /// stash.insert("key", 42);
416    ///
417    /// // Obtain mutable reference to value
418    /// let mut value = stash.get_mut(&"key");
419    /// assert_eq!(value, Some(&mut 42));
420    /// ```
421    #[inline]
422    fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
423    where
424        K: Borrow<Q>,
425        Q: Key,
426    {
427        match self.store.get(key) {
428            Some(&index) => self.items.get_mut(index).map(|(_, value)| value),
429            None => None,
430        }
431    }
432
433    /// Returns a mutable reference to the value or creates the default.
434    ///
435    /// # Examples
436    ///
437    /// ```
438    /// use zrx_store::{Stash, StoreMutRef};
439    ///
440    /// // Create stash
441    /// let mut stash = Stash::<_, i32>::default();
442    ///
443    /// // Obtain mutable reference to value
444    /// let value = stash.get_or_insert_default(&"key");
445    /// assert_eq!(value, &mut 0);
446    /// ```
447    #[inline]
448    fn get_or_insert_default(&mut self, key: &K) -> &mut V
449    where
450        V: Default,
451    {
452        if !self.store.contains_key(key) {
453            let n = self.items.insert((key.clone(), V::default()));
454            self.store.insert(key.clone(), n);
455        }
456
457        // We can safely use expect here, as the key is present
458        self.get_mut(key).expect("invariant")
459    }
460}
461
462// ----------------------------------------------------------------------------
463
464impl<K, V, S> Index<usize> for Stash<K, V, S>
465where
466    K: Key,
467    S: Store<K, usize>,
468{
469    type Output = V;
470
471    /// Returns a reference to the value at the index.
472    ///
473    /// # Panics
474    ///
475    /// Panics if the index is out of bounds.
476    ///
477    /// # Examples
478    ///
479    /// ```
480    /// use zrx_store::Stash;
481    ///
482    /// // Create stash and initial state
483    /// let mut stash = Stash::default();
484    /// stash.insert("a", 42);
485    /// stash.insert("b", 84);
486    ///
487    /// // Obtain reference to value
488    /// let value = &stash[1];
489    /// assert_eq!(value, &84);
490    /// ```
491    #[inline]
492    fn index(&self, index: usize) -> &Self::Output {
493        &self.items[index].1
494    }
495}
496
497impl<K, V, S> IndexMut<usize> for Stash<K, V, S>
498where
499    K: Key,
500    S: Store<K, usize>,
501{
502    /// Returns a mutable reference to the value at the index.
503    ///
504    /// # Panics
505    ///
506    /// Panics if the index is out of bounds.
507    ///
508    /// # Examples
509    ///
510    /// ```
511    /// use zrx_store::Stash;
512    ///
513    /// // Create stash and initial state
514    /// let mut stash = Stash::default();
515    /// stash.insert("a", 42);
516    /// stash.insert("b", 84);
517    ///
518    /// // Obtain mutable reference to value
519    /// let value = &mut stash[1];
520    /// assert_eq!(value, &mut 84);
521    /// ```
522    #[inline]
523    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
524        &mut self.items[index].1
525    }
526}
527
528// ----------------------------------------------------------------------------
529
530impl<K, V, S> FromIterator<(K, V)> for Stash<K, V, S>
531where
532    K: Key,
533    S: StoreMut<K, usize> + Default,
534{
535    /// Creates a stash from an iterator.
536    ///
537    /// # Examples
538    ///
539    /// ```
540    /// use std::collections::HashMap;
541    /// use zrx_store::Stash;
542    ///
543    /// // Create a vector of key-value pairs
544    /// let items = vec![
545    ///     ("a", 1),
546    ///     ("b", 2),
547    ///     ("c", 3),
548    ///     ("d", 4),
549    /// ];
550    ///
551    /// // Create stash from iterator
552    /// let stash: Stash<_, _, HashMap<_, _>> =
553    ///     items.into_iter().collect();
554    ///
555    /// // Create iterator over the stash
556    /// for (key, value) in &stash {
557    ///     println!("{key}: {value}");
558    /// }
559    /// ```
560    #[inline]
561    fn from_iter<T>(iter: T) -> Self
562    where
563        T: IntoIterator<Item = (K, V)>,
564    {
565        let mut store = Stash::new();
566        for (key, value) in iter {
567            store.insert(key, value);
568        }
569        store
570    }
571}
572
573#[allow(clippy::into_iter_without_iter)]
574impl<'a, K, V, S> IntoIterator for &'a Stash<K, V, S>
575where
576    K: Key,
577    V: Value,
578    S: StoreIterable<K, usize>,
579{
580    type Item = (&'a K, &'a V);
581    type IntoIter = Iter<'a, K, V>;
582
583    /// Creates an iterator over the stash.
584    ///
585    /// # Examples
586    ///
587    /// ```
588    /// use zrx_store::Stash;
589    ///
590    /// // Create stash and initial state
591    /// let mut stash = Stash::default();
592    /// stash.insert("key", 42);
593    ///
594    /// // Create iterator over the stash
595    /// for (key, value) in &stash {
596    ///     println!("{key}: {value}");
597    /// }
598    /// ```
599    #[inline]
600    fn into_iter(self) -> Self::IntoIter {
601        StoreIterable::iter(&self.items)
602    }
603}
604
605#[allow(clippy::into_iter_without_iter)]
606impl<'a, K, V, S> IntoIterator for &'a mut Stash<K, V, S>
607where
608    K: Key,
609    V: Value,
610    S: StoreIterableMut<K, usize>,
611{
612    type Item = (&'a K, &'a mut V);
613    type IntoIter = IterMut<'a, K, V>;
614
615    /// Creates a mutable iterator over the stash.
616    ///
617    /// # Examples
618    ///
619    /// ```
620    /// use zrx_store::Stash;
621    ///
622    /// // Create stash and initial state
623    /// let mut stash = Stash::default();
624    /// stash.insert("key", 42);
625    ///
626    /// // Create iterator over the stash
627    /// for (key, value) in &mut stash {
628    ///     println!("{key}: {value}");
629    /// }
630    /// ```
631    #[inline]
632    fn into_iter(self) -> Self::IntoIter {
633        StoreIterableMut::iter_mut(&mut self.items)
634    }
635}
636
637// ----------------------------------------------------------------------------
638
639impl<K, V> Default for Stash<K, V>
640where
641    K: Key,
642{
643    /// Creates a stash with [`HashMap::default`][] as a store.
644    ///
645    /// Note that this method does not allow to customize the [`BuildHasher`][],
646    /// but uses [`ahash`] by default, which is the fastest known hasher.
647    ///
648    /// [`BuildHasher`]: std::hash::BuildHasher
649    /// [`HashMap::default`]: Default::default
650    ///
651    /// # Examples
652    ///
653    /// ```
654    /// use zrx_store::Stash;
655    ///
656    /// // Create stash and initial state
657    /// let mut stash = Stash::default();
658    /// stash.insert("key", 42);
659    /// ```
660    #[inline]
661    fn default() -> Self {
662        Self::new()
663    }
664}
665
666// ----------------------------------------------------------------------------
667
668impl<K, V, S> Debug for Stash<K, V, S>
669where
670    K: Debug,
671    V: Debug,
672    S: Debug,
673{
674    /// Formats the stash for debugging.
675    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
676        f.debug_struct("Stash")
677            .field("store", &self.store)
678            .field("items", &self.items)
679            .finish()
680    }
681}