claude_agent/config/
memory.rs1use std::collections::HashMap;
7use std::sync::Arc;
8
9use tokio::sync::RwLock;
10
11use super::ConfigResult;
12use super::provider::ConfigProvider;
13
14#[derive(Debug, Default)]
16pub struct MemoryConfigProvider {
17 data: Arc<RwLock<HashMap<String, String>>>,
18 name: String,
19}
20
21impl MemoryConfigProvider {
22 pub fn new() -> Self {
24 Self {
25 data: Arc::new(RwLock::new(HashMap::new())),
26 name: "memory".to_string(),
27 }
28 }
29
30 pub fn with_name(name: impl Into<String>) -> Self {
32 Self {
33 data: Arc::new(RwLock::new(HashMap::new())),
34 name: name.into(),
35 }
36 }
37
38 pub fn with_data(data: HashMap<String, String>) -> Self {
40 Self {
41 data: Arc::new(RwLock::new(data)),
42 name: "memory".to_string(),
43 }
44 }
45
46 pub fn with_value(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
48 Arc::get_mut(&mut self.data)
50 .expect("with_value must be called during construction")
51 .get_mut()
52 .insert(key.into(), value.into());
53 self
54 }
55
56 pub async fn insert(&self, key: impl Into<String>, value: impl Into<String>) {
58 let mut data = self.data.write().await;
59 data.insert(key.into(), value.into());
60 }
61
62 pub async fn len(&self) -> usize {
64 self.data.read().await.len()
65 }
66
67 pub async fn is_empty(&self) -> bool {
69 self.data.read().await.is_empty()
70 }
71
72 pub async fn clear(&self) {
74 self.data.write().await.clear();
75 }
76}
77
78#[async_trait::async_trait]
79impl ConfigProvider for MemoryConfigProvider {
80 fn name(&self) -> &str {
81 &self.name
82 }
83
84 async fn get_raw(&self, key: &str) -> ConfigResult<Option<String>> {
85 let data = self.data.read().await;
86 Ok(data.get(key).cloned())
87 }
88
89 async fn set_raw(&self, key: &str, value: &str) -> ConfigResult<()> {
90 let mut data = self.data.write().await;
91 data.insert(key.to_string(), value.to_string());
92 Ok(())
93 }
94
95 async fn delete(&self, key: &str) -> ConfigResult<bool> {
96 let mut data = self.data.write().await;
97 Ok(data.remove(key).is_some())
98 }
99
100 async fn list_keys(&self, prefix: &str) -> ConfigResult<Vec<String>> {
101 let data = self.data.read().await;
102 let keys: Vec<String> = data
103 .keys()
104 .filter(|k| k.starts_with(prefix))
105 .cloned()
106 .collect();
107 Ok(keys)
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[tokio::test]
116 async fn test_memory_provider_basic() {
117 let provider = MemoryConfigProvider::new();
118
119 provider.set_raw("key1", "value1").await.unwrap();
121 let value = provider.get_raw("key1").await.unwrap();
122 assert_eq!(value, Some("value1".to_string()));
123
124 let value = provider.get_raw("nonexistent").await.unwrap();
126 assert_eq!(value, None);
127 }
128
129 #[tokio::test]
130 async fn test_memory_provider_delete() {
131 let provider = MemoryConfigProvider::new();
132
133 provider.set_raw("key1", "value1").await.unwrap();
134 assert!(provider.delete("key1").await.unwrap());
135 assert!(!provider.delete("key1").await.unwrap());
136
137 let value = provider.get_raw("key1").await.unwrap();
138 assert_eq!(value, None);
139 }
140
141 #[tokio::test]
142 async fn test_memory_provider_list_keys() {
143 let provider = MemoryConfigProvider::new();
144
145 provider.set_raw("app.name", "test").await.unwrap();
146 provider.set_raw("app.version", "1.0").await.unwrap();
147 provider.set_raw("other.key", "value").await.unwrap();
148
149 let keys = provider.list_keys("app.").await.unwrap();
150 assert_eq!(keys.len(), 2);
151 assert!(keys.contains(&"app.name".to_string()));
152 assert!(keys.contains(&"app.version".to_string()));
153 }
154
155 #[tokio::test]
156 async fn test_memory_provider_typed() {
157 use crate::config::provider::ConfigProviderExt;
158
159 let provider = MemoryConfigProvider::new();
160
161 ConfigProviderExt::set(&provider, "count", &42i32)
163 .await
164 .unwrap();
165
166 let count: Option<i32> = ConfigProviderExt::get(&provider, "count").await.unwrap();
168 assert_eq!(count, Some(42));
169 }
170
171 #[tokio::test]
172 async fn test_memory_provider_with_data() {
173 let mut data = HashMap::new();
174 data.insert("key1".to_string(), "value1".to_string());
175 data.insert("key2".to_string(), "value2".to_string());
176
177 let provider = MemoryConfigProvider::with_data(data);
178
179 assert_eq!(provider.len().await, 2);
180 assert_eq!(
181 provider.get_raw("key1").await.unwrap(),
182 Some("value1".to_string())
183 );
184 }
185}