zrx_store/store.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//! Store abstractions and implementations with specific characteristics.
27
28use std::borrow::Borrow;
29use std::ops::RangeBounds;
30
31pub mod behavior;
32mod collection;
33pub mod comparator;
34pub mod decorator;
35mod key;
36
37pub use key::Key;
38
39// ----------------------------------------------------------------------------
40// Traits
41// ----------------------------------------------------------------------------
42
43/// Immutable store.
44///
45/// This trait defines the required methods for an immutable key-value store,
46/// which can be used in operators to derive state from items. However, it is
47/// only a foundational trait for a set of traits that define complementary
48/// capabilities for stores, like [`StoreMut`] or [`StoreIterable`].
49///
50/// There are several related traits, all of which can be composed in trait
51/// bounds to require specific store capabilities. These are:
52///
53/// - [`StoreMut`]: Mutable store
54/// - [`StoreMutRef`]: Mutable store that can return mutable references
55/// - [`StoreIterable`]: Immutable store that is iterable
56/// - [`StoreIterableMut`]: Mutable store that is iterable
57/// - [`StoreKeys`]: Immutable store that is iterable over its keys
58/// - [`StoreValues`]: Immutable store that is iterable over its values
59/// - [`StoreRange`]: Immutable store that is iterable over a range
60///
61/// This trait is implemented for [`HashMap`][] and [`BTreeMap`][], as well as
62/// for the third-party [`litemap`] crate, the latter of which is available when
63/// the corresponding feature is enabled. Note that stores are not thread-safe,
64/// so they can't be shared among worker threads.
65///
66/// All methods deliberately have [`Infallible`] signatures, as stores must be
67/// fast and reliable, and should never fail under normal circumstances. Stores
68/// should not need to serialize data, write to the filesystem, or send data
69/// over the network. They should only have in-memory representations.
70///
71/// [`BTreeMap`]: std::collections::BTreeMap
72/// [`HashMap`]: std::collections::HashMap
73/// [`Infallible`]: std::convert::Infallible
74///
75/// # Examples
76///
77/// ```
78/// use std::collections::HashMap;
79/// use zrx_store::StoreMut;
80///
81/// // Create store and initial state
82/// let mut store = HashMap::new();
83/// store.insert("key", 42);
84///
85/// // Obtain reference to value
86/// let value = store.get(&"key");
87/// assert_eq!(value, Some(&42));
88/// ```
89pub trait Store<K, V>
90where
91 K: Key,
92{
93 /// Returns a reference to the value identified by the key.
94 fn get<Q>(&self, key: &Q) -> Option<&V>
95 where
96 K: Borrow<Q>,
97 Q: Key;
98
99 /// Returns whether the store contains the key.
100 fn contains_key<Q>(&self, key: &Q) -> bool
101 where
102 K: Borrow<Q>,
103 Q: Key;
104
105 /// Returns the number of items in the store.
106 fn len(&self) -> usize;
107
108 /// Returns whether the store is empty.
109 #[inline]
110 fn is_empty(&self) -> bool {
111 self.len() == 0
112 }
113}
114
115/// Mutable store.
116///
117/// This trait extends [`Store`], requiring further additional mutable methods
118/// which can be used in operators to derive state from incoming events.
119///
120/// # Examples
121///
122/// ```
123/// use std::collections::HashMap;
124/// use zrx_store::StoreMut;
125///
126/// // Create store and initial state
127/// let mut store = HashMap::new();
128/// store.insert("key", 42);
129///
130/// // Remove value from store
131/// let value = store.remove(&"key");
132/// assert_eq!(value, Some(42));
133/// ```
134pub trait StoreMut<K, V>: Store<K, V>
135where
136 K: Key,
137{
138 /// Inserts the value identified by the key.
139 fn insert(&mut self, key: K, value: V) -> Option<V>;
140
141 /// Inserts the value identified by the key if it changed.
142 fn insert_if_changed(&mut self, key: &K, value: &V) -> bool
143 where
144 V: Clone + Eq,
145 {
146 (self.get(key) != Some(value))
147 .then(|| self.insert(key.clone(), value.clone()))
148 .is_some()
149 }
150
151 /// Removes the value identified by the key.
152 fn remove<Q>(&mut self, key: &Q) -> Option<V>
153 where
154 K: Borrow<Q>,
155 Q: Key;
156
157 /// Removes the value identified by the key and returns both.
158 fn remove_entry<Q>(&mut self, key: &Q) -> Option<(K, V)>
159 where
160 K: Borrow<Q>,
161 Q: Key;
162
163 /// Clears the store, removing all items.
164 fn clear(&mut self);
165}
166
167/// Mutable store that can return mutable references.
168///
169/// This trait extends [`StoreMut`], adding the possibility to obtain mutable
170/// references as a requirement, so values can be mutated in-place.
171///
172/// # Examples
173///
174/// ```
175/// use std::collections::HashMap;
176/// use zrx_store::{StoreMut, StoreMutRef};
177///
178/// // Create store and initial state
179/// let mut store = HashMap::new();
180/// store.insert("key", 42);
181///
182/// // Obtain mutable reference to value
183/// let mut value = store.get_mut(&"key");
184/// assert_eq!(value, Some(&mut 42));
185/// ```
186pub trait StoreMutRef<K, V>: Store<K, V>
187where
188 K: Key,
189{
190 /// Returns a mutable reference to the value identified by the key.
191 fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
192 where
193 K: Borrow<Q>,
194 Q: Key;
195
196 /// Returns a mutable reference to the value or creates the default.
197 fn get_or_insert_default(&mut self, key: &K) -> &mut V
198 where
199 V: Default;
200}
201
202/// Immutable store that is iterable.
203///
204/// This trait extends [`Store`], adding iteration capabilities as a further
205/// requirement, so stores can be enumerated in operators.
206///
207/// # Examples
208///
209/// ```
210/// use std::collections::HashMap;
211/// use zrx_store::{StoreIterable, StoreMut};
212///
213/// // Create store and initial state
214/// let mut store = HashMap::new();
215/// store.insert("key", 42);
216///
217/// // Create iterator over the store
218/// for (key, value) in store.iter() {
219/// println!("{key}: {value}");
220/// }
221/// ```
222pub trait StoreIterable<K, V>: Store<K, V>
223where
224 K: Key,
225{
226 /// Creates an iterator over the store.
227 fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a K, &'a V)>
228 where
229 K: 'a,
230 V: 'a;
231}
232
233/// Mutable store that is iterable.
234///
235/// This trait extends [`StoreMut`], adding mutable iteration capabilities as a
236/// requirement, so stores can be enumerated in operators.
237///
238/// # Examples
239///
240/// ```
241/// use std::collections::HashMap;
242/// use zrx_store::{StoreIterableMut, StoreMut};
243///
244/// // Create store and initial state
245/// let mut store = HashMap::new();
246/// store.insert("key", 42);
247///
248/// // Create iterator over the store
249/// for (key, value) in store.iter_mut() {
250/// println!("{key}: {value}");
251/// }
252/// ```
253pub trait StoreIterableMut<K, V>: StoreMut<K, V>
254where
255 K: Key,
256{
257 /// Creates a mutable iterator over the store.
258 fn iter_mut<'a>(&'a mut self) -> impl Iterator<Item = (&'a K, &'a mut V)>
259 where
260 K: 'a,
261 V: 'a;
262}
263
264/// Immutable store that is iterable over its keys.
265///
266/// This trait extends [`Store`], adding key iteration capabilities as a
267/// requirement, so stores can be enumerated in operators.
268///
269/// # Examples
270///
271/// ```
272/// use std::collections::HashMap;
273/// use zrx_store::{StoreKeys, StoreMut};
274///
275/// // Create store and initial state
276/// let mut store = HashMap::new();
277/// store.insert("key", 42);
278///
279/// // Create iterator over the store
280/// for key in store.keys() {
281/// println!("{key}");
282/// }
283/// ```
284pub trait StoreKeys<K, V>: Store<K, V>
285where
286 K: Key,
287{
288 /// Creates a key iterator over the store.
289 fn keys<'a>(&'a self) -> impl Iterator<Item = &'a K>
290 where
291 K: 'a;
292}
293
294/// Immutable store that is iterable over its values.
295///
296/// This trait extends [`Store`], adding value iteration capabilities as a
297/// requirement, so stores can be enumerated in operators.
298///
299/// # Examples
300///
301/// ```
302/// use std::collections::HashMap;
303/// use zrx_store::{StoreMut, StoreValues};
304///
305/// // Create store and initial state
306/// let mut store = HashMap::new();
307/// store.insert("key", 42);
308///
309/// // Create iterator over the store
310/// for value in store.values() {
311/// println!("{value}");
312/// }
313/// ```
314pub trait StoreValues<K, V>: Store<K, V>
315where
316 K: Key,
317{
318 /// Creates a value iterator over the store.
319 fn values<'a>(&'a self) -> impl Iterator<Item = &'a V>
320 where
321 V: 'a;
322}
323
324/// Immutable store that is iterable over a range.
325///
326/// This trait extends [`Store`], adding iteration capabilities as a further
327/// requirement, so ranges of stores can be enumerated in operators.
328///
329/// # Examples
330///
331/// ```
332/// use std::collections::BTreeMap;
333/// use zrx_store::{StoreMut, StoreRange};
334///
335/// // Create store and initial state
336/// let mut store = BTreeMap::new();
337/// store.insert("a", 42);
338/// store.insert("b", 84);
339///
340/// // Create iterator over the store
341/// for (key, value) in store.range("b"..) {
342/// println!("{key}: {value}");
343/// }
344/// ```
345pub trait StoreRange<K, V>: Store<K, V>
346where
347 K: Key,
348{
349 /// Creates a range iterator over the store.
350 fn range<'a, R>(&'a self, range: R) -> impl Iterator<Item = (&'a K, &'a V)>
351 where
352 R: RangeBounds<K>,
353 K: 'a,
354 V: 'a;
355}
356
357// ----------------------------------------------------------------------------
358
359/// Creates a store from an iterator.
360pub trait StoreFromIterator<K, V>: FromIterator<(K, V)> {}
361
362/// Creates an iterator over the store.
363pub trait StoreIntoIterator<K, V>: IntoIterator<Item = (K, V)> {}
364
365// ----------------------------------------------------------------------------
366// Blanket implementations
367// ----------------------------------------------------------------------------
368
369#[rustfmt::skip]
370impl<K, V, T> StoreFromIterator<K, V> for T
371where
372 T: FromIterator<(K, V)> {}
373
374#[rustfmt::skip]
375impl<K, V, T> StoreIntoIterator<K, V> for T
376where
377 T: IntoIterator<Item = (K, V)> {}