From af1ec73fb5f06d1c137b7f666a16e2a96ad48430 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sat, 13 Apr 2024 02:12:30 -0400 Subject: [PATCH] improve safety by avoiding raw pointers,improve dynamic view code a bit --- lyra-engine | 2 +- src/main.rs | 187 ++++++++++++++++++++++++++++++--------- witguest/src/bindings.rs | 128 ++++++++++++++++++++++++--- witguest/src/lib.rs | 37 ++++---- witguest/wit/world.wit | 8 +- 5 files changed, 287 insertions(+), 75 deletions(-) diff --git a/lyra-engine b/lyra-engine index 60ec62c..12c8ece 160000 --- a/lyra-engine +++ b/lyra-engine @@ -1 +1 @@ -Subproject commit 60ec62c55828a4ea273a10e5614e7cc589b005cf +Subproject commit 12c8ece4183f117864bac362d181ea5906141c6f diff --git a/src/main.rs b/src/main.rs index 2ee33e8..2f0d102 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use std::ptr::NonNull; use async_trait::async_trait; use component::witguest::ecs::WasmTypeId; use component::witguest::{ecs as wasm_ecs, math}; -use ecs::query::dynamic::QueryDynamicType; +use ecs::query::dynamic::{DynamicViewState, DynamicViewStateIter, QueryDynamicType}; use lyra_ecs::Component; use lyra_ecs as ecs; @@ -15,6 +15,8 @@ use slab::Slab; use thiserror::Error; use wasmtime_wasi::WasiView; +use wasmtime::component::Resource as WasmResource; + #[allow(unused_imports)] pub(crate) mod lyra_engine { pub use lyra_ecs as ecs; @@ -69,8 +71,23 @@ struct Vec3 { z: f32, } +struct WorldEntry { + world: lyra_ecs::World, + /// Indices of dynamic views that are still alive + views: Slab, +} + +struct DynamicViewEntry { + /// The index of the world that this view is a part of + world_index: usize, + view: DynamicViewStateIter, +} + +unsafe impl Send for DynamicViewEntry {} + struct Imports { - world_slab: Slab, + world_slab: Slab, + world_views_slab: Slab, } impl WasiView for Imports { @@ -96,20 +113,32 @@ impl math::Host for Imports {} #[derive(Error, Debug)] pub enum WasmError { #[error("an invalid '{0}' resource handle was used by the guest")] - InvalidResourceHandle(&'static str) + InvalidResourceHandle(&'static str), } #[async_trait] impl wasm_ecs::HostEcsWorld for Imports { - async fn new(&mut self,) -> wasmtime::Result> { - let world = self.world_slab.insert(lyra_ecs::World::new()); - Ok(wasmtime::component::Resource::new_own(world as _)) + async fn new(&mut self) -> wasmtime::Result> { + let entry = WorldEntry { + world: lyra_ecs::World::new(), + views: Slab::new(), + }; + let world = self.world_slab.insert(entry); + Ok(WasmResource::new_own(world as _)) } - async fn spawn(&mut self, this: wasmtime::component::Resource, mut components: Vec, infos: Vec) -> wasmtime::Result { - let world = self.world_slab.get_mut(this.rep() as _) + async fn spawn( + &mut self, + this: WasmResource, + mut components: Vec, + infos: Vec, + ) -> wasmtime::Result { + let world_entry = self + .world_slab + .get_mut(this.rep() as _) .ok_or(WasmError::InvalidResourceHandle("EcsWorld"))?; - + let world = &mut world_entry.world; + // add the components in the tightly packed `components` buffer into the dynamic bundle let mut bundle = ecs::DynamicBundle::new(); let mut offset = 0; @@ -126,52 +155,123 @@ impl wasm_ecs::HostEcsWorld for Imports { Ok(en.into()) } - async fn view(&mut self, this: wasmtime::component::Resource, infos: Vec) -> wasmtime::Result> { - let world = self.world_slab.get_mut(this.rep() as _) - .ok_or(WasmError::InvalidResourceHandle("EcsWorld"))?; - - // Create a dynamic view for querying for the components - let mut view = world.dynamic_view(); - for info in infos.clone() { - view.push(QueryDynamicType::from_info(info.into())); - } - - // allocate the row of components - let total_len = infos.iter().map(|i| i.size as usize).sum(); - let mut components = Vec::with_capacity(total_len); - - // copy each row of the query into the set of components. could get pretty big, but its a PoC so :shrug: - for row in view.into_iter() { - let first = row.iter().next().unwrap(); - - let mut comp = Vec::::with_capacity(first.info.layout().size()); - unsafe { - std::ptr::copy_nonoverlapping( - first.ptr.as_ptr(), - comp.as_mut_ptr(), - first.info.layout().size(), - ); - comp.set_len(first.info.layout().size()); - } - components.extend(comp.into_iter()); - } - - Ok(components) + async fn view( + &mut self, + this: wasmtime::component::Resource, + infos: Vec, + ) -> wasmtime::Result> { + ::new(self, this, infos).await } - fn drop(&mut self, this: wasmtime::component::Resource) -> wasmtime::Result<()> { - self.world_slab.try_remove(this.rep() as _) + fn drop( + &mut self, + this: wasmtime::component::Resource, + ) -> wasmtime::Result<()> { + let mut world_entry = self + .world_slab + .try_remove(this.rep() as _) .ok_or(WasmError::InvalidResourceHandle("EcsWorld"))?; + // make sure that all the world views are now dead + for view in world_entry.views.drain() { + self.world_views_slab.remove(view); + } + Ok(()) } } #[async_trait] -impl wasm_ecs::Host for Imports { +impl wasm_ecs::HostEcsDynamicView for Imports { + async fn new( + &mut self, + world: WasmResource, + infos: Vec, + ) -> wasmtime::Result> { + // Create a dynamic view for querying for the components + let mut view = DynamicViewState::new(); + for info in infos.clone() { + view.push(QueryDynamicType::from_info(info.into())); + } + let world_rep = world.rep(); + let entry = DynamicViewEntry { + world_index: world_rep as _, + view: view.into_iter(), + }; + let view_index = self.world_views_slab.insert(entry); + + // link the dynamic view to the world that its a part of. + let world_entry = self + .world_slab + .get_mut(world.rep() as _) + .ok_or(WasmError::InvalidResourceHandle("EcsWorld"))?; + world_entry.views.insert(view_index); + + Ok(WasmResource::new_own(view_index as _)) + } + + async fn next( + &mut self, + view: WasmResource, + ) -> wasmtime::Result>> { + let view_entry = self.world_views_slab.get_mut(view.rep() as _).unwrap(); + let world_entry = self.world_slab.get(view_entry.world_index).unwrap(); + let view = &mut view_entry.view; + + // get the next row in the view and copy the returned components into a tightly packed + if let Some(row) = view.next(&world_entry.world) { + let row_len = row.iter().map(|d| d.info.layout().size()).sum(); + let mut row_buf = Vec::::with_capacity(row_len); + + let mut offset = 0; + for comp in row { + let comp_size = comp.info.layout().size(); + unsafe { + // SAFETY: the vec has the capacity to store this component because it was + // created with Vec::with_capacity. + let dst = row_buf.as_mut_ptr().add(offset); + + std::ptr::copy_nonoverlapping( + comp.ptr.as_ptr(), + dst, + comp.info.layout().size(), + ); + + // make sure to tell the vec that it now has the bytes of this component + row_buf.set_len(row_buf.len() + comp_size); + } + + offset += comp_size; + } + + Ok(Some(row_buf)) + } else { + Ok(None) + } + } + + fn drop( + &mut self, + this: wasmtime::component::Resource, + ) -> wasmtime::Result<()> { + // first delete the actual view + let view_rep = this.rep() as usize; + let view = self.world_views_slab.get(view_rep).unwrap(); + let view_world = view.world_index; + + // now remove the link to the view inside of the world entry + self.world_views_slab.remove(view_rep); + let world = self.world_slab.get_mut(view_world).unwrap(); + world.views.remove(view_rep); + + Ok(()) + } } +#[async_trait] +impl wasm_ecs::Host for Imports {} + #[tokio::main] async fn main() -> wasmtime::Result<()> { // Instantiate the engine and store @@ -192,6 +292,7 @@ async fn main() -> wasmtime::Result<()> { // There will likely be a world, but a slab is used in the case that the guest // wants another world for some reason. world_slab: Slab::with_capacity(1), + world_views_slab: Slab::with_capacity(10), }, ); diff --git a/witguest/src/bindings.rs b/witguest/src/bindings.rs index e7b615e..59a5963 100644 --- a/witguest/src/bindings.rs +++ b/witguest/src/bindings.rs @@ -132,6 +132,47 @@ pub mod component { } } + #[derive(Debug)] + #[repr(transparent)] + pub struct EcsDynamicView{ + handle: wit_bindgen::rt::Resource, + } + + impl EcsDynamicView{ + #[doc(hidden)] + pub unsafe fn from_handle(handle: u32) -> Self { + Self { + handle: wit_bindgen::rt::Resource::from_handle(handle), + } + } + + #[doc(hidden)] + pub fn handle(&self) -> u32 { + wit_bindgen::rt::Resource::handle(&self.handle) + } + } + + + unsafe impl wit_bindgen::rt::WasmResource for EcsDynamicView{ + #[inline] + unsafe fn drop(_handle: u32) { + #[cfg(not(target_arch = "wasm32"))] + unreachable!(); + + #[cfg(target_arch = "wasm32")] + { + #[link(wasm_import_module = "component:witguest/ecs")] + extern "C" { + #[link_name = "[resource-drop]ecs-dynamic-view"] + fn drop(_: u32); + } + + drop(_handle); + } + } + } + + #[derive(Debug)] #[repr(transparent)] pub struct EcsWorld{ @@ -172,6 +213,71 @@ pub mod component { } } + impl EcsDynamicView { + #[allow(unused_unsafe, clippy::all)] + pub fn new(wrld: &EcsWorld,component_infos: &[ComponentInfo],) -> Self{ + + #[allow(unused_imports)] + use wit_bindgen::rt::{alloc, vec::Vec, string::String}; + unsafe { + let vec0 = component_infos; + let ptr0 = vec0.as_ptr() as i32; + let len0 = vec0.len() as i32; + + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "component:witguest/ecs")] + extern "C" { + #[link_name = "[constructor]ecs-dynamic-view"] + fn wit_import(_: i32, _: i32, _: i32, ) -> i32; + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, _: i32, ) -> i32{ unreachable!() } + let ret = wit_import((wrld).handle() as i32, ptr0, len0); + EcsDynamicView::from_handle(ret as u32) + } + } + } + impl EcsDynamicView { + #[allow(unused_unsafe, clippy::all)] + pub fn next(&self,) -> Option>{ + + #[allow(unused_imports)] + use wit_bindgen::rt::{alloc, vec::Vec, string::String}; + unsafe { + + #[repr(align(4))] + struct RetArea([u8; 12]); + let mut ret_area = ::core::mem::MaybeUninit::::uninit(); + let ptr0 = ret_area.as_mut_ptr() as i32; + #[cfg(target_arch = "wasm32")] + #[link(wasm_import_module = "component:witguest/ecs")] + extern "C" { + #[link_name = "[method]ecs-dynamic-view.next"] + fn wit_import(_: i32, _: i32, ); + } + + #[cfg(not(target_arch = "wasm32"))] + fn wit_import(_: i32, _: i32, ){ unreachable!() } + wit_import((self).handle() as i32, ptr0); + let l1 = i32::from(*((ptr0 + 0) as *const u8)); + match l1 { + 0 => None, + 1 => { + let e = { + let l2 = *((ptr0 + 4) as *const i32); + let l3 = *((ptr0 + 8) as *const i32); + let len4 = l3 as usize; + + Vec::from_raw_parts(l2 as *mut _, len4, len4) + }; + Some(e) + } + _ => wit_bindgen::rt::invalid_enum_discriminant(), + } + } + } + } impl EcsWorld { #[allow(unused_unsafe, clippy::all)] pub fn new() -> Self{ @@ -196,6 +302,7 @@ pub mod component { } impl EcsWorld { #[allow(unused_unsafe, clippy::all)] + /// expects components to be tightly packed in the same order of component-infos pub fn spawn(&self,components: &[u8],component_infos: &[ComponentInfo],) -> Entity{ #[allow(unused_imports)] @@ -235,33 +342,26 @@ pub mod component { } impl EcsWorld { #[allow(unused_unsafe, clippy::all)] - pub fn view(&self,component_infos: &[ComponentInfo],) -> wit_bindgen::rt::vec::Vec::{ + pub fn view(&self,component_infos: &[ComponentInfo],) -> EcsDynamicView{ #[allow(unused_imports)] use wit_bindgen::rt::{alloc, vec::Vec, string::String}; unsafe { - - #[repr(align(4))] - struct RetArea([u8; 8]); - let mut ret_area = ::core::mem::MaybeUninit::::uninit(); let vec0 = component_infos; let ptr0 = vec0.as_ptr() as i32; let len0 = vec0.len() as i32; - let ptr1 = ret_area.as_mut_ptr() as i32; + #[cfg(target_arch = "wasm32")] #[link(wasm_import_module = "component:witguest/ecs")] extern "C" { #[link_name = "[method]ecs-world.view"] - fn wit_import(_: i32, _: i32, _: i32, _: i32, ); + fn wit_import(_: i32, _: i32, _: i32, ) -> i32; } #[cfg(not(target_arch = "wasm32"))] - fn wit_import(_: i32, _: i32, _: i32, _: i32, ){ unreachable!() } - wit_import((self).handle() as i32, ptr0, len0, ptr1); - let l2 = *((ptr1 + 0) as *const i32); - let l3 = *((ptr1 + 4) as *const i32); - let len4 = l3 as usize; - Vec::from_raw_parts(l2 as *mut _, len4, len4) + fn wit_import(_: i32, _: i32, _: i32, ) -> i32{ unreachable!() } + let ret = wit_import((self).handle() as i32, ptr0, len0); + EcsDynamicView::from_handle(ret as u32) } } } @@ -274,7 +374,7 @@ pub mod component { #[cfg(target_arch = "wasm32")] #[link_section = "component-type:example"] #[doc(hidden)] -pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 608] = [0, 97, 115, 109, 13, 0, 1, 0, 0, 25, 22, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 4, 0, 7, 227, 3, 1, 65, 2, 1, 65, 9, 1, 66, 2, 1, 114, 3, 1, 120, 118, 1, 121, 118, 1, 122, 118, 4, 0, 4, 118, 101, 99, 51, 3, 0, 0, 3, 1, 23, 99, 111, 109, 112, 111, 110, 101, 110, 116, 58, 119, 105, 116, 103, 117, 101, 115, 116, 47, 109, 97, 116, 104, 5, 0, 1, 66, 20, 1, 114, 1, 2, 105, 100, 119, 4, 0, 9, 101, 110, 116, 105, 116, 121, 45, 105, 100, 3, 0, 0, 1, 114, 2, 2, 105, 100, 1, 10, 103, 101, 110, 101, 114, 97, 116, 105, 111, 110, 119, 4, 0, 6, 101, 110, 116, 105, 116, 121, 3, 0, 2, 1, 111, 2, 119, 119, 1, 114, 1, 5, 105, 110, 110, 101, 114, 4, 4, 0, 12, 119, 97, 115, 109, 45, 116, 121, 112, 101, 45, 105, 100, 3, 0, 5, 1, 114, 3, 4, 115, 105, 122, 101, 119, 9, 97, 108, 105, 103, 110, 109, 101, 110, 116, 119, 7, 116, 121, 112, 101, 45, 105, 100, 6, 4, 0, 14, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 105, 110, 102, 111, 3, 0, 7, 4, 0, 9, 101, 99, 115, 45, 119, 111, 114, 108, 100, 3, 1, 1, 105, 9, 1, 64, 0, 0, 10, 4, 0, 22, 91, 99, 111, 110, 115, 116, 114, 117, 99, 116, 111, 114, 93, 101, 99, 115, 45, 119, 111, 114, 108, 100, 1, 11, 1, 104, 9, 1, 112, 125, 1, 112, 8, 1, 64, 3, 4, 115, 101, 108, 102, 12, 10, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 13, 15, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 105, 110, 102, 111, 115, 14, 0, 3, 4, 0, 23, 91, 109, 101, 116, 104, 111, 100, 93, 101, 99, 115, 45, 119, 111, 114, 108, 100, 46, 115, 112, 97, 119, 110, 1, 15, 1, 64, 2, 4, 115, 101, 108, 102, 12, 15, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 105, 110, 102, 111, 115, 14, 0, 13, 4, 0, 22, 91, 109, 101, 116, 104, 111, 100, 93, 101, 99, 115, 45, 119, 111, 114, 108, 100, 46, 118, 105, 101, 119, 1, 16, 3, 1, 22, 99, 111, 109, 112, 111, 110, 101, 110, 116, 58, 119, 105, 116, 103, 117, 101, 115, 116, 47, 101, 99, 115, 5, 1, 1, 64, 1, 3, 109, 115, 103, 115, 1, 0, 3, 0, 10, 104, 111, 115, 116, 45, 112, 114, 105, 110, 116, 1, 2, 1, 106, 1, 125, 0, 1, 64, 0, 0, 3, 4, 0, 7, 111, 110, 45, 105, 110, 105, 116, 1, 4, 4, 1, 26, 99, 111, 109, 112, 111, 110, 101, 110, 116, 58, 119, 105, 116, 103, 117, 101, 115, 116, 47, 101, 120, 97, 109, 112, 108, 101, 4, 0, 11, 13, 1, 0, 7, 101, 120, 97, 109, 112, 108, 101, 3, 0, 0, 0, 70, 9, 112, 114, 111, 100, 117, 99, 101, 114, 115, 1, 12, 112, 114, 111, 99, 101, 115, 115, 101, 100, 45, 98, 121, 2, 13, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 6, 48, 46, 50, 49, 46, 48, 16, 119, 105, 116, 45, 98, 105, 110, 100, 103, 101, 110, 45, 114, 117, 115, 116, 6, 48, 46, 49, 56, 46, 48]; +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 745] = [0, 97, 115, 109, 13, 0, 1, 0, 0, 25, 22, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 101, 110, 99, 111, 100, 105, 110, 103, 4, 0, 7, 236, 4, 1, 65, 2, 1, 65, 9, 1, 66, 2, 1, 114, 3, 1, 120, 118, 1, 121, 118, 1, 122, 118, 4, 0, 4, 118, 101, 99, 51, 3, 0, 0, 3, 1, 23, 99, 111, 109, 112, 111, 110, 101, 110, 116, 58, 119, 105, 116, 103, 117, 101, 115, 116, 47, 109, 97, 116, 104, 5, 0, 1, 66, 28, 1, 114, 1, 2, 105, 100, 119, 4, 0, 9, 101, 110, 116, 105, 116, 121, 45, 105, 100, 3, 0, 0, 1, 114, 2, 2, 105, 100, 1, 10, 103, 101, 110, 101, 114, 97, 116, 105, 111, 110, 119, 4, 0, 6, 101, 110, 116, 105, 116, 121, 3, 0, 2, 1, 111, 2, 119, 119, 1, 114, 1, 5, 105, 110, 110, 101, 114, 4, 4, 0, 12, 119, 97, 115, 109, 45, 116, 121, 112, 101, 45, 105, 100, 3, 0, 5, 1, 114, 3, 4, 115, 105, 122, 101, 119, 9, 97, 108, 105, 103, 110, 109, 101, 110, 116, 119, 7, 116, 121, 112, 101, 45, 105, 100, 6, 4, 0, 14, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 105, 110, 102, 111, 3, 0, 7, 4, 0, 16, 101, 99, 115, 45, 100, 121, 110, 97, 109, 105, 99, 45, 118, 105, 101, 119, 3, 1, 4, 0, 9, 101, 99, 115, 45, 119, 111, 114, 108, 100, 3, 1, 1, 104, 10, 1, 112, 8, 1, 105, 9, 1, 64, 2, 4, 119, 114, 108, 100, 11, 15, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 105, 110, 102, 111, 115, 12, 0, 13, 4, 0, 29, 91, 99, 111, 110, 115, 116, 114, 117, 99, 116, 111, 114, 93, 101, 99, 115, 45, 100, 121, 110, 97, 109, 105, 99, 45, 118, 105, 101, 119, 1, 14, 1, 104, 9, 1, 112, 125, 1, 107, 16, 1, 64, 1, 4, 115, 101, 108, 102, 15, 0, 17, 4, 0, 29, 91, 109, 101, 116, 104, 111, 100, 93, 101, 99, 115, 45, 100, 121, 110, 97, 109, 105, 99, 45, 118, 105, 101, 119, 46, 110, 101, 120, 116, 1, 18, 1, 105, 10, 1, 64, 0, 0, 19, 4, 0, 22, 91, 99, 111, 110, 115, 116, 114, 117, 99, 116, 111, 114, 93, 101, 99, 115, 45, 119, 111, 114, 108, 100, 1, 20, 1, 64, 3, 4, 115, 101, 108, 102, 11, 10, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 16, 15, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 105, 110, 102, 111, 115, 12, 0, 3, 4, 0, 23, 91, 109, 101, 116, 104, 111, 100, 93, 101, 99, 115, 45, 119, 111, 114, 108, 100, 46, 115, 112, 97, 119, 110, 1, 21, 1, 64, 2, 4, 115, 101, 108, 102, 11, 15, 99, 111, 109, 112, 111, 110, 101, 110, 116, 45, 105, 110, 102, 111, 115, 12, 0, 13, 4, 0, 22, 91, 109, 101, 116, 104, 111, 100, 93, 101, 99, 115, 45, 119, 111, 114, 108, 100, 46, 118, 105, 101, 119, 1, 22, 3, 1, 22, 99, 111, 109, 112, 111, 110, 101, 110, 116, 58, 119, 105, 116, 103, 117, 101, 115, 116, 47, 101, 99, 115, 5, 1, 1, 64, 1, 3, 109, 115, 103, 115, 1, 0, 3, 0, 10, 104, 111, 115, 116, 45, 112, 114, 105, 110, 116, 1, 2, 1, 106, 1, 125, 0, 1, 64, 0, 0, 3, 4, 0, 7, 111, 110, 45, 105, 110, 105, 116, 1, 4, 4, 1, 26, 99, 111, 109, 112, 111, 110, 101, 110, 116, 58, 119, 105, 116, 103, 117, 101, 115, 116, 47, 101, 120, 97, 109, 112, 108, 101, 4, 0, 11, 13, 1, 0, 7, 101, 120, 97, 109, 112, 108, 101, 3, 0, 0, 0, 70, 9, 112, 114, 111, 100, 117, 99, 101, 114, 115, 1, 12, 112, 114, 111, 99, 101, 115, 115, 101, 100, 45, 98, 121, 2, 13, 119, 105, 116, 45, 99, 111, 109, 112, 111, 110, 101, 110, 116, 6, 48, 46, 50, 49, 46, 48, 16, 119, 105, 116, 45, 98, 105, 110, 100, 103, 101, 110, 45, 114, 117, 115, 116, 6, 48, 46, 49, 56, 46, 48]; #[inline(never)] #[doc(hidden)] diff --git a/witguest/src/lib.rs b/witguest/src/lib.rs index 14651a1..058bf0b 100644 --- a/witguest/src/lib.rs +++ b/witguest/src/lib.rs @@ -1,7 +1,7 @@ #[allow(warnings)] mod bindings; -use bindings::{component::witguest::ecs::{ComponentInfo, EcsWorld, WasmTypeId}, Guest}; +use bindings::{component::witguest::ecs::{ComponentInfo, EcsWorld, Entity, WasmTypeId}, Guest}; use std::{alloc::Layout, any::TypeId, mem}; @@ -42,25 +42,30 @@ struct Component; impl Guest for Component { fn on_init() -> Result { - let comps = &mut [Vec3::new(7.0, 30.0, 18.0),]; - let info = &[Vec3::component_info()]; - - // no fucking clue if this will work, but lets try and it see - let comps = comps.as_mut_ptr().cast::(); - let comps = unsafe { Vec::from_raw_parts(comps, mem::size_of::(), 1) }; - let world = EcsWorld::new(); - let en = world.spawn(&comps, info); + spawn_vec3(&world, Vec3::new(7.0, 30.0, 18.0)); + spawn_vec3(&world, Vec3::new(90.30, 65.0, 83.0)); - //let en = ecs_world::spawn(&comps, info); + bindings::host_print("Spawned entities"); - bindings::host_print(&format!("Spawned entity: {}", en.id.id)); - - let mut buffer = world.view(&[Vec3::component_info()]); - bindings::host_print(&format!("Retrieved vec3 of {} bytes long", buffer.len())); - let fetched_vec = unsafe { std::ptr::read(buffer.as_mut_ptr().cast::()) }; - bindings::host_print(&format!("Retrieved vec3: {:?}", fetched_vec)); + let view = world.view(&[Vec3::component_info()]); + while let Some(mut buffer) = view.next() { + bindings::host_print(&format!("Retrieved vec3 of {} bytes long", buffer.len())); + let fetched_vec = unsafe { std::ptr::read(buffer.as_mut_ptr().cast::()) }; + bindings::host_print(&format!("Retrieved vec3: {:?}", fetched_vec)); + } Ok(0) } +} + +fn spawn_vec3(world: &EcsWorld, v: Vec3) -> Entity { + let comps = &mut [v,]; + let info = &[Vec3::component_info()]; + + // no fucking clue if this will work, but lets try and it see + let comps = comps.as_mut_ptr().cast::(); + let comps = unsafe { Vec::from_raw_parts(comps, mem::size_of::(), 1) }; + + world.spawn(&comps, info) } \ No newline at end of file diff --git a/witguest/wit/world.wit b/witguest/wit/world.wit index 578ec1e..18be241 100644 --- a/witguest/wit/world.wit +++ b/witguest/wit/world.wit @@ -30,12 +30,18 @@ interface ecs { type-id: wasm-type-id, // a u128 } + resource ecs-dynamic-view { + constructor(wrld: borrow, component-infos: list); + + next: func() -> option>; + } + resource ecs-world { constructor(); // expects components to be tightly packed in the same order of component-infos spawn: func(components: list, component-infos: list) -> entity; - view: func(component-infos: list) -> list; + view: func(component-infos: list) -> ecs-dynamic-view; } }