zrx_store/
store.rs

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