diff options
| author | Mica White <botahamec@outlook.com> | 2026-10-26 10:52:04 -0400 |
|---|---|---|
| committer | Mica White <botahamec@outlook.com> | 2026-10-26 10:58:46 -0400 |
| commit | ec40f6e3acc7874b82709ab81b254c741529fdff (patch) | |
| tree | e3dfdc315bd0c6f1d2efcf442c2cfb3317d6810f /platforms/tortuise-script-wasm/src/state.rs | |
| parent | e3c5839159903658a667f789963f20a31567b25c (diff) | |
Diffstat (limited to 'platforms/tortuise-script-wasm/src/state.rs')
| -rw-r--r-- | platforms/tortuise-script-wasm/src/state.rs | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/platforms/tortuise-script-wasm/src/state.rs b/platforms/tortuise-script-wasm/src/state.rs new file mode 100644 index 0000000..ffcdb3e --- /dev/null +++ b/platforms/tortuise-script-wasm/src/state.rs @@ -0,0 +1,102 @@ +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(); + if layout.size() == 0 { + return None; + } + 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); + } +} |
