diff options
Diffstat (limited to 'src/state.rs')
| -rw-r--r-- | src/state.rs | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..8b4de18 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,99 @@ +use core::{ + alloc::Layout, + ops::{Deref, DerefMut}, +}; + +use alloc::alloc::{alloc, dealloc}; +use serde::{Serialize, de::DeserializeOwned}; + +use crate::ScriptContext; + +mod tortuise { + #[link(wasm_import_module = "tortuise")] + unsafe extern "C" { + pub safe fn state_size(context: u64) -> usize; + pub unsafe fn load_state(context: u64, offset: *mut u8); + pub unsafe fn save_state(context: u64, offset: *const u8, size: usize); + + } +} + +impl ScriptContext { + pub fn load_state<T: DeserializeOwned>(&self) -> Option<T> { + unsafe { + let size = tortuise::state_size(self.0); + let layout = Layout::array::<u8>(size).unwrap(); + let ptr = alloc(layout); + tortuise::load_state(self.0, ptr); + let data = core::slice::from_raw_parts(ptr, size); + let data = messagepack_serde::from_reader(data).ok()?; + dealloc(ptr, layout); + Some(data) + } + } +} + +fn save_state<T: Serialize>(context: u64, state: &T) { + unsafe { + let data = messagepack_serde::to_vec(state).unwrap(); + tortuise::save_state(context, data.as_ptr(), data.len()); + } +} + +pub struct StateMut<T: Serialize> { + context: u64, + data: T, +} + +impl<T: Serialize + DeserializeOwned> StateMut<T> { + pub fn load(context: &ScriptContext) -> Option<Self> { + Some(Self { + context: context.0, + data: context.load_state()?, + }) + } + + pub fn load_or(context: &ScriptContext, default: T) -> Self { + Self { + context: context.0, + data: context.load_state().unwrap_or(default), + } + } + + pub fn load_or_else(context: &ScriptContext, default: impl FnOnce() -> T) -> Self { + Self { + context: context.0, + data: context.load_state().unwrap_or_else(default), + } + } + + pub fn load_or_default(context: &ScriptContext) -> Self + where + T: Default, + { + Self { + context: context.0, + data: context.load_state().unwrap_or_default(), + } + } +} + +impl<T: Serialize> Deref for StateMut<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + +impl<T: Serialize> DerefMut for StateMut<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.data + } +} + +impl<T: Serialize> Drop for StateMut<T> { + fn drop(&mut self) { + save_state(self.context, &self.data); + } +} |
