use crate::error::ContextError;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::Debug;
use tracing::{debug, warn};
#[derive(Debug)]
pub struct Context<T>
where
T: Serialize + for<'de> Deserialize<'de> + Debug,
{
data: HashMap<String, T>,
}
impl<T> Context<T>
where
T: Serialize + for<'de> Deserialize<'de> + Debug,
{
pub fn new() -> Self {
debug!("Creating new empty context");
Self {
data: HashMap::new(),
}
}
pub fn clone_data(&self) -> Self
where
T: Clone,
{
debug!("Cloning context data");
Self {
data: self.data.clone(),
}
}
pub fn insert(&mut self, key: impl Into<String>, value: T) -> Result<(), ContextError> {
let key = key.into();
if self.data.contains_key(&key) {
warn!("Attempted to insert duplicate key: {}", key);
return Err(ContextError::KeyExists(key));
}
debug!("Inserting value for key: {}", key);
self.data.insert(key, value);
Ok(())
}
pub fn update(&mut self, key: impl Into<String>, value: T) -> Result<(), ContextError> {
let key = key.into();
if !self.data.contains_key(&key) {
warn!("Attempted to update non-existent key: {}", key);
return Err(ContextError::KeyNotFound(key));
}
debug!("Updating value for key: {}", key);
self.data.insert(key, value);
Ok(())
}
pub fn get(&self, key: &str) -> Option<&T> {
debug!("Getting value for key: {}", key);
self.data.get(key)
}
pub fn remove(&mut self, key: &str) -> Option<T> {
debug!("Removing value for key: {}", key);
self.data.remove(key)
}
pub fn data(&self) -> &HashMap<String, T> {
&self.data
}
pub fn into_data(self) -> HashMap<String, T> {
self.data
}
pub fn from_data(data: HashMap<String, T>) -> Self {
Self { data }
}
pub fn to_json(&self) -> Result<String, ContextError> {
debug!("Serializing context to JSON");
let json = serde_json::to_string(&self.data)?;
debug!("Context serialized successfully");
Ok(json)
}
pub fn from_json(json: String) -> Result<Self, ContextError> {
debug!("Deserializing context from JSON");
let data = serde_json::from_str(&json)?;
debug!("Context deserialized successfully");
Ok(Self { data })
}
}
impl<T> Default for Context<T>
where
T: Serialize + for<'de> Deserialize<'de> + Debug,
{
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn setup_test_context() -> Context<i32> {
Context::new()
}
#[test]
fn test_context_operations() {
let mut context = setup_test_context();
assert!(context.data.is_empty());
context.insert("test", 42).unwrap();
assert_eq!(context.get("test"), Some(&42));
assert!(matches!(
context.insert("test", 43),
Err(ContextError::KeyExists(_))
));
context.update("test", 43).unwrap();
assert_eq!(context.get("test"), Some(&43));
assert!(matches!(
context.update("nonexistent", 42),
Err(ContextError::KeyNotFound(_))
));
}
#[test]
fn test_context_serialization() {
let mut context = setup_test_context();
context.insert("test", 42).unwrap();
let json = context.to_json().unwrap();
let deserialized = Context::<i32>::from_json(json).unwrap();
assert_eq!(deserialized.get("test"), Some(&42));
}
#[test]
fn test_context_clone_data() {
let mut context = Context::<i32>::new();
context.insert("a", 1).unwrap();
context.insert("b", 2).unwrap();
let cloned = context.clone_data();
assert_eq!(cloned.get("a"), Some(&1));
assert_eq!(cloned.get("b"), Some(&2));
}
#[test]
fn test_context_from_data() {
let mut data = HashMap::new();
data.insert("key".to_string(), 42);
let context = Context::from_data(data);
assert_eq!(context.get("key"), Some(&42));
}
#[test]
fn test_context_into_data() {
let mut context = Context::<i32>::new();
context.insert("key", 42).unwrap();
let data = context.into_data();
assert_eq!(data.get("key"), Some(&42));
}
}