summaryrefslogtreecommitdiff
path: root/platforms/tortuise-script-compiled/src/storage.rs
diff options
context:
space:
mode:
Diffstat (limited to 'platforms/tortuise-script-compiled/src/storage.rs')
-rw-r--r--platforms/tortuise-script-compiled/src/storage.rs181
1 files changed, 181 insertions, 0 deletions
diff --git a/platforms/tortuise-script-compiled/src/storage.rs b/platforms/tortuise-script-compiled/src/storage.rs
new file mode 100644
index 0000000..d028a91
--- /dev/null
+++ b/platforms/tortuise-script-compiled/src/storage.rs
@@ -0,0 +1,181 @@
+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 });
+ }
+}