Skip to main content

millipede_core/storage/
kvs.rs

1//! Key-value storage contracts.
2
3use super::StorageResult;
4use serde::{Serialize, de::DeserializeOwned};
5
6/// A stored byte value and its metadata.
7#[derive(Debug, Clone)]
8pub struct KvEntry {
9    /// Storage key.
10    pub key: String,
11    /// Stored bytes.
12    pub value: bytes::Bytes,
13    /// MIME content type.
14    pub content_type: String,
15}
16
17/// Options controlling key pagination.
18#[derive(Debug, Clone, Default)]
19#[non_exhaustive]
20#[must_use = "list options do nothing unless passed to KeyValueStore::list_keys"]
21pub struct ListKeysOptions {
22    /// Maximum number of keys to return.
23    pub limit: Option<usize>,
24    /// Key after which listing begins.
25    pub exclusive_start_key: Option<String>,
26}
27
28/// Metadata for one stored key.
29#[derive(Debug, Clone)]
30pub struct KeyInfo {
31    /// Storage key.
32    pub key: String,
33    /// Value size in bytes.
34    pub size: u64,
35}
36
37/// A page of keys and continuation metadata.
38#[derive(Debug, Clone)]
39pub struct KeyList {
40    /// Keys in this page.
41    pub keys: Vec<KeyInfo>,
42    /// Whether more keys remain.
43    pub is_truncated: bool,
44    /// Continuation key for the next page.
45    pub next_exclusive_start_key: Option<String>,
46}
47
48/// Object-safe byte-oriented key-value storage.
49#[async_trait::async_trait]
50pub trait KeyValueStore: Send + Sync {
51    /// Gets a stored byte value.
52    async fn get_bytes(&self, key: &str) -> StorageResult<Option<KvEntry>>;
53    /// Sets a stored byte value and content type.
54    async fn set_bytes(
55        &self,
56        key: &str,
57        bytes: bytes::Bytes,
58        content_type: &str,
59    ) -> StorageResult<()>;
60    /// Deletes a key, doing nothing when it is absent.
61    async fn delete(&self, key: &str) -> StorageResult<()>;
62    /// Lists stored keys.
63    async fn list_keys(&self, opts: ListKeysOptions) -> StorageResult<KeyList>;
64}
65
66/// Typed JSON convenience operations available on every [`KeyValueStore`].
67#[async_trait::async_trait]
68pub trait KeyValueStoreExt: KeyValueStore {
69    /// Gets and deserializes a JSON value.
70    async fn get<T: DeserializeOwned + 'static>(&self, key: &str) -> StorageResult<Option<T>> {
71        match self.get_bytes(key).await? {
72            Some(entry) => Ok(Some(serde_json::from_slice(&entry.value)?)),
73            None => Ok(None),
74        }
75    }
76
77    /// Serializes and stores a JSON value.
78    async fn set<T: Serialize + Send + Sync>(&self, key: &str, value: &T) -> StorageResult<()> {
79        self.set_bytes(key, serde_json::to_vec(value)?.into(), "application/json")
80            .await
81    }
82}
83
84impl<K: KeyValueStore + ?Sized> KeyValueStoreExt for K {}