use core::ops::{Deref, DerefMut}; use serde::{Serialize, de::DeserializeOwned}; use spin::Mutex; use tortuise::script::Operation; use crate::ScriptContext; pub struct Storage { initial_state: fn() -> T, data: Mutex>, } pub struct Config { initial_state: fn() -> T, data: Mutex>, } pub struct StorageMut<'a, 'cx, T: Serialize + Eq> { context: &'cx mut ScriptContext<'a>, data: T, original: T, } pub struct ConfigMut<'a, 'cx, T: Serialize + Eq> { context: &'cx mut ScriptContext<'a>, data: T, original: T, } impl Storage { pub const fn new(initial_state: fn() -> T) -> Self { Self { initial_state, data: Mutex::new(None), } } pub fn load(&self, context: &ScriptContext) -> T { puffin::profile_function!(); let mut data = self.data.lock(); data.get_or_insert_with(|| { context .0 .storage .data() .map(messagepack_serde::from_slice) .and_then(|r| r.ok()) .unwrap_or_else(self.initial_state) }) .clone() } pub fn load_mut<'a, 'cx>(&self, context: &'cx mut ScriptContext<'a>) -> StorageMut<'a, 'cx, T> { let data = self.load(context); StorageMut { original: data.clone(), data, context, } } pub fn is_saving(&self, context: &ScriptContext) -> bool { context.0.storage.is_saving_data() } pub fn save_failed(&self, context: &ScriptContext) -> bool { context.0.storage.saving_data_failed() } } impl Config { pub const fn new(initial_state: fn() -> T) -> Self { Self { initial_state, data: Mutex::new(None), } } pub fn load(&self, context: &ScriptContext) -> T { puffin::profile_function!(); let mut data = self.data.lock(); data.get_or_insert_with(|| { context .0 .storage .config() .map(toml::from_slice) .and_then(|r| r.ok()) .unwrap_or_else(self.initial_state) }) .clone() } pub fn load_mut<'a, 'cx>(&self, context: &'cx mut ScriptContext<'a>) -> StorageMut<'a, 'cx, T> { let data = self.load(context); StorageMut { original: data.clone(), data, context, } } pub fn is_saving(&self, context: &ScriptContext) -> bool { context.0.storage.is_saving_config() } pub fn save_failed(&self, context: &ScriptContext) -> bool { context.0.storage.saving_config_failed() } } impl Deref for StorageMut<'_, '_, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.data } } impl DerefMut for StorageMut<'_, '_, T> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.data } } impl Drop for StorageMut<'_, '_, T> { fn drop(&mut self) { puffin::profile_function!(); if self.data == self.original { return; } let new_save = match messagepack_serde::to_vec(&self.data) { Ok(new_save) => new_save.into_boxed_slice(), Err(e) => { log::error!("{e}"); return; } }; self.context .0 .operation_queue .push(Operation::UpdateStorage { new_save }); } } impl Deref for ConfigMut<'_, '_, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.data } } impl DerefMut for ConfigMut<'_, '_, T> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.data } } impl Drop for ConfigMut<'_, '_, T> { fn drop(&mut self) { puffin::profile_function!(); if self.data == self.original { return; } let new_save = match toml::to_string(&self.data) { Ok(new_save) => new_save.as_bytes().into(), Err(e) => { log::error!("{e}"); return; } }; self.context .0 .operation_queue .push(Operation::UpdateConfig { new_save }); } }