Skip to main content

commonware_storage/kv/
mod.rs

1//! Traits for interacting with a key/value store.
2
3use commonware_macros::{stability, stability_mod};
4
5stability_mod!(ALPHA, mod batch);
6#[stability(ALPHA)]
7pub use batch::{Batch, Batchable};
8use std::future::Future;
9
10/// A readable key-value store.
11pub trait Gettable {
12    type Key: Send + Sync;
13    type Value: Send + Sync;
14    type Error;
15
16    /// Get the value of a key.
17    fn get<'a>(
18        &'a self,
19        key: &'a Self::Key,
20    ) -> impl Future<Output = Result<Option<Self::Value>, Self::Error>> + Send + use<'a, Self>;
21}
22
23/// A mutable key-value store.
24pub trait Updatable: Gettable {
25    /// Update the value of a key.
26    fn update<'a>(
27        &'a mut self,
28        key: Self::Key,
29        value: Self::Value,
30    ) -> impl Future<Output = Result<(), Self::Error>> + Send + use<'a, Self>;
31
32    /// Creates a new key-value pair in the db. Returns true if the key was created, false if it
33    /// already existed. The key is not modified if it already existed.
34    fn create<'a>(
35        &'a mut self,
36        key: Self::Key,
37        value: Self::Value,
38    ) -> impl Future<Output = Result<bool, Self::Error>> + Send + use<'a, Self>
39    where
40        Self: Send,
41    {
42        async {
43            if self.get(&key).await?.is_some() {
44                return Ok(false);
45            }
46            self.update(key, value).await?;
47            Ok(true)
48        }
49    }
50
51    /// Updates the value associated with the given key in the store, inserting a default value if
52    /// the key does not already exist.
53    fn upsert<'a, F>(
54        &'a mut self,
55        key: Self::Key,
56        update: F,
57    ) -> impl Future<Output = Result<(), Self::Error>> + Send + use<'a, Self, F>
58    where
59        Self: Send,
60        Self::Value: Default,
61        F: FnOnce(&mut Self::Value) + Send + 'a,
62    {
63        async move {
64            let mut value = self.get(&key).await?.unwrap_or_default();
65            update(&mut value);
66            self.update(key, value).await
67        }
68    }
69}
70
71/// A mutable key-value store that supports deleting values.
72pub trait Deletable: Updatable {
73    /// Delete the value of a key.
74    ///
75    /// Returns `true` if the key existed and was deleted, `false` if it did not exist.
76    fn delete<'a>(
77        &'a mut self,
78        key: Self::Key,
79    ) -> impl Future<Output = Result<bool, Self::Error>> + Send + use<'a, Self>;
80}
81
82#[cfg(test)]
83pub(crate) mod tests {
84    use super::{Batchable, Deletable, Gettable, Updatable};
85    use commonware_codec::DecodeExt;
86    use commonware_utils::sequence::FixedBytes;
87
88    pub fn assert_send<T: Send>(_: T) {}
89
90    /// Create a test key from a string.
91    pub fn test_key(key: &str) -> FixedBytes<64> {
92        let mut buf = [0u8; 64];
93        let key = key.as_bytes();
94        assert!(key.len() <= buf.len());
95        buf[..key.len()].copy_from_slice(key);
96        FixedBytes::decode(buf.as_ref()).unwrap()
97    }
98
99    #[allow(dead_code)]
100    pub fn assert_gettable<T: Gettable + Send>(db: &T, key: &T::Key) {
101        assert_send(db.get(key));
102    }
103
104    #[allow(dead_code)]
105    pub fn assert_updatable<T: Updatable + Send>(db: &mut T, key: T::Key, value: T::Value)
106    where
107        T::Key: Clone,
108        T::Value: Default + Clone,
109    {
110        assert_send(db.update(key.clone(), value.clone()));
111        assert_send(db.create(key.clone(), value));
112        assert_send(db.upsert(key, |_| {}));
113    }
114
115    #[allow(dead_code)]
116    pub fn assert_deletable<T: Deletable + Send>(db: &mut T, key: T::Key) {
117        assert_send(db.delete(key));
118    }
119
120    #[allow(dead_code)]
121    pub fn assert_batchable<T: Batchable + Send>(db: &mut T, key: T::Key, value: T::Value) {
122        assert_send(db.write_batch(vec![(key, Some(value))].into_iter()));
123    }
124}