use dusa_collection_utils::core::errors::ErrorArrayItem;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CustomConfig(HashMap<String, Value>);
impl CustomConfig {
pub fn new() -> Self {
Self::default()
}
pub fn get<T: DeserializeOwned>(&self, key: &str) -> Option<T> {
self.0
.get(key)
.and_then(|value| serde_json::from_value(value.clone()).ok())
}
pub fn get_or<T: DeserializeOwned>(&self, key: &str, default: T) -> T {
self.get(key).unwrap_or(default)
}
pub fn contains(&self, key: &str) -> bool {
self.0.contains_key(key)
}
pub fn set<T: Serialize>(&mut self, key: &str, value: T) -> Result<(), ErrorArrayItem> {
let json = serde_json::to_value(value).map_err(ErrorArrayItem::from)?;
self.0.insert(key.to_owned(), json);
Ok(())
}
pub fn remove(&mut self, key: &str) {
self.0.remove(key);
}
pub fn to_json(&self) -> Result<String, ErrorArrayItem> {
serde_json::to_string_pretty(&self.0).map_err(ErrorArrayItem::from)
}
pub fn from_json(data: &str) -> Result<Self, ErrorArrayItem> {
let map: HashMap<String, Value> = serde_json::from_str(data).map_err(ErrorArrayItem::from)?;
Ok(Self(map))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn missing_key_is_none_not_an_error() {
let config = CustomConfig::new();
assert_eq!(config.get::<String>("nope"), None);
assert_eq!(config.get_or("nope", "fallback".to_string()), "fallback");
}
#[test]
fn wrong_shape_is_none_not_an_error() {
let mut config = CustomConfig::new();
config.set("count", "not-a-number").unwrap();
assert_eq!(config.get::<u32>("count"), None);
}
#[test]
fn round_trips_through_json() {
let mut config = CustomConfig::new();
config.set("feature_flag", true).unwrap();
config.set("retries", 3u32).unwrap();
let json = config.to_json().unwrap();
let restored = CustomConfig::from_json(&json).unwrap();
assert_eq!(restored.get::<bool>("feature_flag"), Some(true));
assert_eq!(restored.get::<u32>("retries"), Some(3));
assert!(restored.contains("feature_flag"));
assert!(!restored.contains("absent"));
}
#[test]
fn remove_drops_a_key() {
let mut config = CustomConfig::new();
config.set("temp", 1u32).unwrap();
config.remove("temp");
assert!(!config.contains("temp"));
}
}