use crate::Error;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
#[derive(Clone)]
pub struct Vault {
data: Arc<RwLock<HashMap<String, serde_json::Value>>>,
}
impl Vault {
pub fn new() -> Self {
Self {
data: Arc::new(RwLock::new(HashMap::new())),
}
}
pub fn set<K: Into<String>, V: serde::Serialize>(&self, key: K, value: V) -> Result<(), Error> {
let json_value = serde_json::to_value(value)
.map_err(|e| Error::vault(format!("Failed to serialize value: {}", e)))?;
self.data
.write()
.map_err(|e| Error::vault(format!("Failed to acquire write lock: {}", e)))?
.insert(key.into(), json_value);
Ok(())
}
pub fn get<K: AsRef<str>, V: for<'de> serde::Deserialize<'de>>(
&self,
key: K,
) -> Result<Option<V>, Error> {
let data = self
.data
.read()
.map_err(|e| Error::vault(format!("Failed to acquire read lock: {}", e)))?;
match data.get(key.as_ref()) {
Some(value) => {
let typed_value = serde_json::from_value(value.clone())
.map_err(|e| Error::vault(format!("Failed to deserialize value: {}", e)))?;
Ok(Some(typed_value))
}
None => Ok(None),
}
}
pub fn contains_key<K: AsRef<str>>(&self, key: K) -> bool {
self.data
.read()
.map(|data| data.contains_key(key.as_ref()))
.unwrap_or(false)
}
pub fn remove<K: AsRef<str>>(&self, key: K) -> Result<(), Error> {
self.data
.write()
.map_err(|e| Error::vault(format!("Failed to acquire write lock: {}", e)))?
.remove(key.as_ref());
Ok(())
}
pub fn clear(&self) -> Result<(), Error> {
self.data
.write()
.map_err(|e| Error::vault(format!("Failed to acquire write lock: {}", e)))?
.clear();
Ok(())
}
pub fn keys(&self) -> Result<Vec<String>, Error> {
let data = self
.data
.read()
.map_err(|e| Error::vault(format!("Failed to acquire read lock: {}", e)))?;
Ok(data.keys().cloned().collect())
}
pub fn len(&self) -> usize {
self.data.read().map(|data| data.len()).unwrap_or(0)
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl Default for Vault {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vault_basic_operations() {
let vault = Vault::new();
vault.set("key1", "value1").unwrap();
assert_eq!(vault.get::<_, String>("key1").unwrap(), Some("value1".to_string()));
assert!(vault.contains_key("key1"));
assert!(!vault.contains_key("key2"));
vault.remove("key1").unwrap();
assert!(!vault.contains_key("key1"));
}
#[test]
fn test_vault_typed_values() {
let vault = Vault::new();
vault.set("int", 42i32).unwrap();
vault.set("float", 3.14f64).unwrap();
vault.set("bool", true).unwrap();
vault.set("string", "hello").unwrap();
assert_eq!(vault.get::<_, i32>("int").unwrap(), Some(42));
assert_eq!(vault.get::<_, f64>("float").unwrap(), Some(3.14));
assert_eq!(vault.get::<_, bool>("bool").unwrap(), Some(true));
assert_eq!(vault.get::<_, String>("string").unwrap(), Some("hello".to_string()));
}
#[test]
fn test_vault_clear() {
let vault = Vault::new();
vault.set("key1", "value1").unwrap();
vault.set("key2", "value2").unwrap();
assert_eq!(vault.len(), 2);
vault.clear().unwrap();
assert_eq!(vault.len(), 0);
assert!(vault.is_empty());
}
#[test]
fn test_vault_clone() {
let vault1 = Vault::new();
vault1.set("key", "value").unwrap();
let vault2 = vault1.clone();
assert_eq!(vault2.get::<_, String>("key").unwrap(), Some("value".to_string()));
vault2.set("key2", "value2").unwrap();
assert!(vault1.contains_key("key2"));
}
}