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)> {}