use core::ops::{Deref, DerefMut};
use serde::{Serialize, de::DeserializeOwned};
use spin::Mutex;
use tortuise::script::Operation;
use crate::ScriptContext;
pub struct Storage<T> {
initial_state: fn() -> T,
data: Mutex<Option<T>>,
}
pub struct Config<T> {
initial_state: fn() -> T,
data: Mutex<Option<T>>,
}
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<T: Serialize + DeserializeOwned + Clone + Eq> Storage<T> {
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<T: Serialize + DeserializeOwned + Clone + Eq> Config<T> {
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<T: Serialize + Eq> Deref for StorageMut<'_, '_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T: Serialize + Eq> DerefMut for StorageMut<'_, '_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<T: Serialize + Eq> 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<T: Serialize + Eq> Deref for ConfigMut<'_, '_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T: Serialize + Eq> DerefMut for ConfigMut<'_, '_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<T: Serialize + Eq> 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 });
}
}
|