diff options
Diffstat (limited to 'src/entity.rs')
| -rw-r--r-- | src/entity.rs | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/src/entity.rs b/src/entity.rs new file mode 100644 index 0000000..9cf6f17 --- /dev/null +++ b/src/entity.rs @@ -0,0 +1,133 @@ +use core::{ + alloc::Layout, + marker::PhantomData, + ops::{Deref, DerefMut}, +}; + +use alloc::{ + alloc::{alloc, dealloc}, + borrow::Cow, + string::String, +}; +use serde::{Deserialize, Serialize}; + +use crate::ScriptContext; + +mod tortuise { + #[link(wasm_import_module = "tortuise")] + unsafe extern "C" { + pub unsafe fn entity_size(context: u64, name: *const u8, name_len: usize) -> usize; + pub unsafe fn load_entity(context: u64, name: *const u8, name_len: usize, offset: *mut u8); + pub unsafe fn save_entity( + context: u64, + name: *const u8, + name_len: usize, + offset: *const u8, + size: usize, + ); + } +} + +fn load_entity<'de, T: Deserialize<'de>>(context: u64, name: &str) -> Option<T> { + unsafe { + let size = tortuise::entity_size(context, name.as_ptr(), name.len()); + let Ok(layout) = Layout::array::<u8>(size) else { + log::error!("Failed to create layout for size: {size}"); + panic!(); + }; + let ptr = alloc(layout); + tortuise::load_entity(context, name.as_ptr(), name.len(), ptr); + let data = core::slice::from_raw_parts(ptr, size); + let data = messagepack_serde::from_slice(data).ok()?; + dealloc(ptr, layout); + Some(data) + } +} + +fn save_entity<T: Serialize>(context: u64, name: &str, state: &T) { + unsafe { + let data = messagepack_serde::to_vec(state).unwrap(); + tortuise::save_entity( + context, + name.as_ptr(), + name.len(), + data.as_ptr(), + data.len(), + ); + } +} + +pub struct Entity<T> { + name: Cow<'static, str>, + default: fn() -> T, +} + +pub struct EntityRef<'entity, T> { + entity: PhantomData<&'entity Entity<T>>, + data: T, +} + +pub struct EntityMut<'entity, T: Serialize> { + context: u64, + entity: &'entity Entity<T>, + data: T, +} + +impl<'de, T: Serialize + Deserialize<'de>> Entity<T> { + pub const fn new(name: &'static str, default: fn() -> T) -> Self { + Self { + name: Cow::Borrowed(name), + default, + } + } + + pub const fn from_string(name: String, default: fn() -> T) -> Self { + Self { + name: Cow::Owned(name), + default, + } + } + + pub fn get(&self, context: &ScriptContext) -> EntityRef<'_, T> { + EntityRef { + entity: PhantomData, + data: load_entity(context.0, &self.name).unwrap_or_else(self.default), + } + } + + pub fn get_mut(&mut self, context: &ScriptContext) -> EntityMut<'_, T> { + EntityMut { + context: context.0, + entity: self, + data: load_entity(context.0, &self.name).unwrap_or_else(self.default), + } + } +} + +impl<T> Deref for EntityRef<'_, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + +impl<T: Serialize> Deref for EntityMut<'_, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + +impl<T: Serialize> DerefMut for EntityMut<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.data + } +} + +impl<T: Serialize> Drop for EntityMut<'_, T> { + fn drop(&mut self) { + save_entity(self.context, &self.entity.name, &self.data); + } +} |
