use std::collections::HashMap;
use std::path::{Path, PathBuf};
pub struct SdlStateStore {
save_dir: PathBuf,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(untagged)]
pub enum SdlValue {
Int(i64),
Float(f64),
Bool(bool),
String(String),
Tuple(Vec<SdlValue>),
}
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct AgeSdlState {
pub variables: HashMap<String, Vec<SdlValue>>,
}
impl SdlStateStore {
pub fn new(save_dir: &Path) -> Self {
Self {
save_dir: save_dir.to_path_buf(),
}
}
pub fn load(&self, age_name: &str) -> AgeSdlState {
let path = self.state_path(age_name);
match std::fs::read_to_string(&path) {
Ok(json) => {
match serde_json::from_str::<AgeSdlState>(&json) {
Ok(state) => {
log::info!("SDL: Loaded {} saved variables for '{}'",
state.variables.len(), age_name);
state
}
Err(e) => {
log::warn!("SDL: Failed to parse {}: {}", path.display(), e);
AgeSdlState::default()
}
}
}
Err(_) => AgeSdlState::default(),
}
}
pub fn save(&self, age_name: &str, state: &AgeSdlState) {
if state.variables.is_empty() {
return;
}
if let Err(e) = std::fs::create_dir_all(&self.save_dir) {
log::warn!("SDL: Failed to create save dir: {}", e);
return;
}
let path = self.state_path(age_name);
match serde_json::to_string_pretty(state) {
Ok(json) => {
if let Err(e) = std::fs::write(&path, json) {
log::warn!("SDL: Failed to write {}: {}", path.display(), e);
} else {
log::info!("SDL: Saved {} variables for '{}' to {}",
state.variables.len(), age_name, path.display());
}
}
Err(e) => log::warn!("SDL: Failed to serialize state: {}", e),
}
}
pub fn set_var(&self, age_name: &str, var_name: &str, values: Vec<SdlValue>) {
let mut state = self.load(age_name);
state.variables.insert(var_name.to_string(), values);
self.save(age_name, &state);
}
fn state_path(&self, age_name: &str) -> PathBuf {
self.save_dir.join(format!("{}_sdl.json", age_name))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sdl_state_roundtrip() {
let dir = std::env::temp_dir().join("plasma_sdl_test");
let _ = std::fs::remove_dir_all(&dir);
let store = SdlStateStore::new(&dir);
let state = store.load("TestAge");
assert!(state.variables.is_empty());
let mut state = AgeSdlState::default();
state.variables.insert("testBool".into(), vec![SdlValue::Bool(true)]);
state.variables.insert("testInt".into(), vec![SdlValue::Int(42)]);
store.save("TestAge", &state);
let loaded = store.load("TestAge");
assert_eq!(loaded.variables.len(), 2);
assert!(matches!(&loaded.variables["testBool"][0], SdlValue::Bool(true)));
assert!(matches!(&loaded.variables["testInt"][0], SdlValue::Int(42)));
let _ = std::fs::remove_dir_all(&dir);
}
}