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 { unsafe { let size = tortuise::entity_size(context, name.as_ptr(), name.len()); let Ok(layout) = Layout::array::(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(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 { name: Cow<'static, str>, default: fn() -> T, } pub struct EntityRef<'entity, T> { entity: PhantomData<&'entity Entity>, data: T, } pub struct EntityMut<'entity, T: Serialize> { context: u64, entity: &'entity Entity, data: T, } impl<'de, T: Serialize + Deserialize<'de>> Entity { 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 Deref for EntityRef<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.data } } impl Deref for EntityMut<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { &self.data } } impl DerefMut for EntityMut<'_, T> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.data } } impl Drop for EntityMut<'_, T> { fn drop(&mut self) { save_entity(self.context, &self.entity.name, &self.data); } }