summaryrefslogtreecommitdiff
path: root/src/state.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/state.rs')
-rw-r--r--src/state.rs99
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);
+ }
+}