icarus_core/
persistent.rs

1//! Persistent state management for servers
2
3use crate::error::Result;
4use async_trait::async_trait;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8/// Trait for managing persistent state
9#[async_trait]
10pub trait IcarusPersistentState: Send + Sync {
11    /// Save a value to persistent storage
12    async fn set(&mut self, key: String, value: Vec<u8>) -> Result<()>;
13
14    /// Retrieve a value from persistent storage
15    async fn get(&self, key: &str) -> Result<Option<Vec<u8>>>;
16
17    /// Delete a value from persistent storage
18    async fn delete(&mut self, key: &str) -> Result<()>;
19
20    /// List all keys in persistent storage
21    async fn list_keys(&self) -> Result<Vec<String>>;
22
23    /// Clear all persistent storage
24    async fn clear(&mut self) -> Result<()>;
25
26    /// Get storage size in bytes
27    async fn size(&self) -> Result<u64>;
28}
29
30/// Helper methods for typed storage
31pub trait TypedPersistentState: IcarusPersistentState {
32    /// Save a typed value
33    fn set_typed<T: Serialize + Send + Sync>(
34        &mut self,
35        key: String,
36        value: &T,
37    ) -> impl std::future::Future<Output = Result<()>> + Send
38    where
39        Self: Send,
40    {
41        async move {
42            let bytes =
43                serde_json::to_vec(value).map_err(crate::error::IcarusError::Serialization)?;
44            self.set(key, bytes).await
45        }
46    }
47
48    /// Get a typed value
49    fn get_typed<T: for<'de> Deserialize<'de> + Send>(
50        &self,
51        key: &str,
52    ) -> impl std::future::Future<Output = Result<Option<T>>> + Send
53    where
54        Self: Send + Sync,
55    {
56        async move {
57            match self.get(key).await? {
58                Some(bytes) => {
59                    let value = serde_json::from_slice(&bytes)
60                        .map_err(crate::error::IcarusError::Serialization)?;
61                    Ok(Some(value))
62                }
63                None => Ok(None),
64            }
65        }
66    }
67}
68
69/// Automatically implement TypedPersistentState for all IcarusPersistentState
70impl<T: IcarusPersistentState + ?Sized> TypedPersistentState for T {}
71
72/// In-memory implementation for testing
73pub struct MemoryPersistentState {
74    data: HashMap<String, Vec<u8>>,
75}
76
77impl MemoryPersistentState {
78    /// Create new in-memory persistent state
79    pub fn new() -> Self {
80        Self {
81            data: HashMap::new(),
82        }
83    }
84}
85
86impl Default for MemoryPersistentState {
87    fn default() -> Self {
88        Self::new()
89    }
90}
91
92#[async_trait]
93impl IcarusPersistentState for MemoryPersistentState {
94    async fn set(&mut self, key: String, value: Vec<u8>) -> Result<()> {
95        self.data.insert(key, value);
96        Ok(())
97    }
98
99    async fn get(&self, key: &str) -> Result<Option<Vec<u8>>> {
100        Ok(self.data.get(key).cloned())
101    }
102
103    async fn delete(&mut self, key: &str) -> Result<()> {
104        self.data.remove(key);
105        Ok(())
106    }
107
108    async fn list_keys(&self) -> Result<Vec<String>> {
109        Ok(self.data.keys().cloned().collect())
110    }
111
112    async fn clear(&mut self) -> Result<()> {
113        self.data.clear();
114        Ok(())
115    }
116
117    async fn size(&self) -> Result<u64> {
118        let size: usize = self.data.values().map(|v| v.len()).sum();
119        Ok(size as u64)
120    }
121}