Skip to main content

millipede_core/storage/
auto_saved.rs

1//! Typed persisted state wrapper.
2
3use super::{KeyValueStore, KeyValueStoreExt, StorageResult};
4use serde::{Serialize, de::DeserializeOwned};
5use std::{fmt, sync::Arc};
6
7/// A typed value that can be explicitly persisted to a key-value store.
8///
9/// The engine calls [`Self::persist`] on every `PersistState` event when Phase 2 wires events to
10/// storage.
11pub struct AutoSaved<T> {
12    store: Arc<dyn KeyValueStore>,
13    key: String,
14    value: tokio::sync::RwLock<T>,
15}
16
17impl<T> fmt::Debug for AutoSaved<T> {
18    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
19        formatter
20            .debug_struct("AutoSaved")
21            .field("key", &self.key)
22            .finish_non_exhaustive()
23    }
24}
25
26impl<T: Serialize + DeserializeOwned + Send + Sync + 'static> AutoSaved<T> {
27    /// Opens a persisted value, falling back to `default` when the key is absent.
28    pub async fn open(
29        store: Arc<dyn KeyValueStore>,
30        key: impl Into<String>,
31        default: T,
32    ) -> StorageResult<Self> {
33        let key = key.into();
34        let value = store.get(&key).await?.unwrap_or(default);
35        Ok(Self {
36            store,
37            key,
38            value: tokio::sync::RwLock::new(value),
39        })
40    }
41
42    /// Clones and returns the current value.
43    pub async fn get(&self) -> T
44    where
45        T: Clone,
46    {
47        self.value.read().await.clone()
48    }
49
50    /// Replaces the current in-memory value without persisting it.
51    pub async fn set(&self, value: T) {
52        *self.value.write().await = value;
53    }
54
55    /// Mutates the current in-memory value without persisting it.
56    pub async fn update<F: FnOnce(&mut T) + Send>(&self, f: F) {
57        f(&mut *self.value.write().await);
58    }
59
60    /// Serializes and persists the current value as JSON.
61    pub async fn persist(&self) -> StorageResult<()> {
62        let bytes = serde_json::to_vec(&*self.value.read().await)?;
63        self.store
64            .set_bytes(&self.key, bytes.into(), "application/json")
65            .await
66    }
67}