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