use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct StatContext {
data: FxHashMap<String, serde_json::Value>,
}
impl StatContext {
pub fn new() -> Self {
Self::default()
}
pub fn set(&mut self, key: impl Into<String>, value: impl Serialize) {
if let Ok(json_value) = serde_json::to_value(value) {
self.data.insert(key.into(), json_value);
}
}
pub fn get<T: for<'de> Deserialize<'de>>(&self, key: &str) -> Option<T> {
self.data
.get(key)
.and_then(|v| serde_json::from_value(v.clone()).ok())
}
pub fn contains_key(&self, key: &str) -> bool {
self.data.contains_key(key)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_context_set_get() {
let mut ctx = StatContext::new();
ctx.set("difficulty", 5);
let difficulty: Option<i32> = ctx.get("difficulty");
assert_eq!(difficulty, Some(5));
}
#[test]
fn test_context_missing_key() {
let ctx = StatContext::new();
let value: Option<i32> = ctx.get("missing");
assert_eq!(value, None);
}
#[test]
fn test_context_different_types() {
let mut ctx = StatContext::new();
ctx.set("int", 42);
ctx.set("float", 3.5);
ctx.set("bool", true);
ctx.set("string", "hello");
ctx.set("vec", vec![1, 2, 3]);
assert_eq!(ctx.get::<i32>("int"), Some(42));
assert_eq!(ctx.get::<f64>("float"), Some(3.5));
assert_eq!(ctx.get::<bool>("bool"), Some(true));
assert_eq!(ctx.get::<String>("string"), Some("hello".to_string()));
assert_eq!(ctx.get::<Vec<i32>>("vec"), Some(vec![1, 2, 3]));
}
#[test]
fn test_context_type_mismatch() {
let mut ctx = StatContext::new();
ctx.set("value", 42);
let result: Option<String> = ctx.get("value");
assert_eq!(result, None);
}
#[test]
fn test_context_contains_key() {
let mut ctx = StatContext::new();
ctx.set("key1", "value1");
assert!(ctx.contains_key("key1"));
assert!(!ctx.contains_key("key2"));
}
#[test]
fn test_context_overwrite() {
let mut ctx = StatContext::new();
ctx.set("value", 10);
assert_eq!(ctx.get::<i32>("value"), Some(10));
ctx.set("value", 20);
assert_eq!(ctx.get::<i32>("value"), Some(20));
}
#[test]
fn test_context_serialization() {
use serde_json;
let mut ctx = StatContext::new();
ctx.set("int", 42);
ctx.set("string", "hello");
let json = serde_json::to_string(&ctx).unwrap();
assert!(json.contains("int"));
assert!(json.contains("hello"));
let deserialized: StatContext = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.get::<i32>("int"), Some(42));
assert_eq!(
deserialized.get::<String>("string"),
Some("hello".to_string())
);
}
#[test]
fn test_context_clone() {
let mut ctx1 = StatContext::new();
ctx1.set("value", 42);
let ctx2 = ctx1.clone();
assert_eq!(ctx2.get::<i32>("value"), Some(42));
ctx1.set("value", 100);
assert_eq!(ctx1.get::<i32>("value"), Some(100));
assert_eq!(ctx2.get::<i32>("value"), Some(42));
}
}