improve safety by avoiding raw pointers,improve dynamic view code a bit

This commit is contained in:
SeanOMik 2024-04-13 02:12:30 -04:00
parent 5d9843cdb0
commit af1ec73fb5
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
5 changed files with 287 additions and 75 deletions

@ -1 +1 @@
Subproject commit 60ec62c55828a4ea273a10e5614e7cc589b005cf Subproject commit 12c8ece4183f117864bac362d181ea5906141c6f

View File

@ -6,7 +6,7 @@ use std::ptr::NonNull;
use async_trait::async_trait; use async_trait::async_trait;
use component::witguest::ecs::WasmTypeId; use component::witguest::ecs::WasmTypeId;
use component::witguest::{ecs as wasm_ecs, math}; 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::Component;
use lyra_ecs as ecs; use lyra_ecs as ecs;
@ -15,6 +15,8 @@ use slab::Slab;
use thiserror::Error; use thiserror::Error;
use wasmtime_wasi::WasiView; use wasmtime_wasi::WasiView;
use wasmtime::component::Resource as WasmResource;
#[allow(unused_imports)] #[allow(unused_imports)]
pub(crate) mod lyra_engine { pub(crate) mod lyra_engine {
pub use lyra_ecs as ecs; pub use lyra_ecs as ecs;
@ -69,8 +71,23 @@ struct Vec3 {
z: f32, z: f32,
} }
struct WorldEntry {
world: lyra_ecs::World,
/// Indices of dynamic views that are still alive
views: Slab<usize>,
}
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 { struct Imports {
world_slab: Slab<lyra_ecs::World>, world_slab: Slab<WorldEntry>,
world_views_slab: Slab<DynamicViewEntry>,
} }
impl WasiView for Imports { impl WasiView for Imports {
@ -96,19 +113,31 @@ impl math::Host for Imports {}
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum WasmError { pub enum WasmError {
#[error("an invalid '{0}' resource handle was used by the guest")] #[error("an invalid '{0}' resource handle was used by the guest")]
InvalidResourceHandle(&'static str) InvalidResourceHandle(&'static str),
} }
#[async_trait] #[async_trait]
impl wasm_ecs::HostEcsWorld for Imports { impl wasm_ecs::HostEcsWorld for Imports {
async fn new(&mut self,) -> wasmtime::Result<wasmtime::component::Resource<wasm_ecs::EcsWorld>> { async fn new(&mut self) -> wasmtime::Result<WasmResource<wasm_ecs::EcsWorld>> {
let world = self.world_slab.insert(lyra_ecs::World::new()); let entry = WorldEntry {
Ok(wasmtime::component::Resource::new_own(world as _)) 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<wasm_ecs::EcsWorld>, mut components: Vec<u8>, infos: Vec<wasm_ecs::ComponentInfo>) -> wasmtime::Result<wasm_ecs::Entity> { async fn spawn(
let world = self.world_slab.get_mut(this.rep() as _) &mut self,
this: WasmResource<wasm_ecs::EcsWorld>,
mut components: Vec<u8>,
infos: Vec<wasm_ecs::ComponentInfo>,
) -> wasmtime::Result<wasm_ecs::Entity> {
let world_entry = self
.world_slab
.get_mut(this.rep() as _)
.ok_or(WasmError::InvalidResourceHandle("EcsWorld"))?; .ok_or(WasmError::InvalidResourceHandle("EcsWorld"))?;
let world = &mut world_entry.world;
// add the components in the tightly packed `components` buffer into the dynamic bundle // add the components in the tightly packed `components` buffer into the dynamic bundle
let mut bundle = ecs::DynamicBundle::new(); let mut bundle = ecs::DynamicBundle::new();
@ -126,52 +155,123 @@ impl wasm_ecs::HostEcsWorld for Imports {
Ok(en.into()) Ok(en.into())
} }
async fn view(&mut self, this: wasmtime::component::Resource<wasm_ecs::EcsWorld>, infos: Vec<wasm_ecs::ComponentInfo>) -> wasmtime::Result<Vec<u8>> { async fn view(
let world = self.world_slab.get_mut(this.rep() as _) &mut self,
this: wasmtime::component::Resource<wasm_ecs::EcsWorld>,
infos: Vec<wasm_ecs::ComponentInfo>,
) -> wasmtime::Result<wasmtime::component::Resource<wasm_ecs::EcsDynamicView>> {
<Self as wasm_ecs::HostEcsDynamicView>::new(self, this, infos).await
}
fn drop(
&mut self,
this: wasmtime::component::Resource<wasm_ecs::EcsWorld>,
) -> wasmtime::Result<()> {
let mut world_entry = self
.world_slab
.try_remove(this.rep() as _)
.ok_or(WasmError::InvalidResourceHandle("EcsWorld"))?; .ok_or(WasmError::InvalidResourceHandle("EcsWorld"))?;
// Create a dynamic view for querying for the components // make sure that all the world views are now dead
let mut view = world.dynamic_view(); for view in world_entry.views.drain() {
for info in infos.clone() { self.world_views_slab.remove(view);
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::<u8>::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)
}
fn drop(&mut self, this: wasmtime::component::Resource<wasm_ecs::EcsWorld>) -> wasmtime::Result<()> {
self.world_slab.try_remove(this.rep() as _)
.ok_or(WasmError::InvalidResourceHandle("EcsWorld"))?;
Ok(()) Ok(())
} }
} }
#[async_trait] #[async_trait]
impl wasm_ecs::Host for Imports { impl wasm_ecs::HostEcsDynamicView for Imports {
async fn new(
&mut self,
world: WasmResource<wasm_ecs::EcsWorld>,
infos: Vec<wasm_ecs::ComponentInfo>,
) -> wasmtime::Result<wasmtime::component::Resource<wasm_ecs::EcsDynamicView>> {
// 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<wasm_ecs::EcsDynamicView>,
) -> wasmtime::Result<Option<Vec<u8>>> {
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::<u8>::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<wasm_ecs::EcsDynamicView>,
) -> 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] #[tokio::main]
async fn main() -> wasmtime::Result<()> { async fn main() -> wasmtime::Result<()> {
// Instantiate the engine and store // 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 // There will likely be a world, but a slab is used in the case that the guest
// wants another world for some reason. // wants another world for some reason.
world_slab: Slab::with_capacity(1), world_slab: Slab::with_capacity(1),
world_views_slab: Slab::with_capacity(10),
}, },
); );

View File

@ -132,6 +132,47 @@ pub mod component {
} }
} }
#[derive(Debug)]
#[repr(transparent)]
pub struct EcsDynamicView{
handle: wit_bindgen::rt::Resource<EcsDynamicView>,
}
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)] #[derive(Debug)]
#[repr(transparent)] #[repr(transparent)]
pub struct EcsWorld{ 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<wit_bindgen::rt::vec::Vec::<u8>>{
#[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::<RetArea>::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 { impl EcsWorld {
#[allow(unused_unsafe, clippy::all)] #[allow(unused_unsafe, clippy::all)]
pub fn new() -> Self{ pub fn new() -> Self{
@ -196,6 +302,7 @@ pub mod component {
} }
impl EcsWorld { impl EcsWorld {
#[allow(unused_unsafe, clippy::all)] #[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{ pub fn spawn(&self,components: &[u8],component_infos: &[ComponentInfo],) -> Entity{
#[allow(unused_imports)] #[allow(unused_imports)]
@ -235,33 +342,26 @@ pub mod component {
} }
impl EcsWorld { impl EcsWorld {
#[allow(unused_unsafe, clippy::all)] #[allow(unused_unsafe, clippy::all)]
pub fn view(&self,component_infos: &[ComponentInfo],) -> wit_bindgen::rt::vec::Vec::<u8>{ pub fn view(&self,component_infos: &[ComponentInfo],) -> EcsDynamicView{
#[allow(unused_imports)] #[allow(unused_imports)]
use wit_bindgen::rt::{alloc, vec::Vec, string::String}; use wit_bindgen::rt::{alloc, vec::Vec, string::String};
unsafe { unsafe {
#[repr(align(4))]
struct RetArea([u8; 8]);
let mut ret_area = ::core::mem::MaybeUninit::<RetArea>::uninit();
let vec0 = component_infos; let vec0 = component_infos;
let ptr0 = vec0.as_ptr() as i32; let ptr0 = vec0.as_ptr() as i32;
let len0 = vec0.len() as i32; let len0 = vec0.len() as i32;
let ptr1 = ret_area.as_mut_ptr() as i32;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
#[link(wasm_import_module = "component:witguest/ecs")] #[link(wasm_import_module = "component:witguest/ecs")]
extern "C" { extern "C" {
#[link_name = "[method]ecs-world.view"] #[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"))] #[cfg(not(target_arch = "wasm32"))]
fn wit_import(_: i32, _: i32, _: i32, _: i32, ){ unreachable!() } fn wit_import(_: i32, _: i32, _: i32, ) -> i32{ unreachable!() }
wit_import((self).handle() as i32, ptr0, len0, ptr1); let ret = wit_import((self).handle() as i32, ptr0, len0);
let l2 = *((ptr1 + 0) as *const i32); EcsDynamicView::from_handle(ret as u32)
let l3 = *((ptr1 + 4) as *const i32);
let len4 = l3 as usize;
Vec::from_raw_parts(l2 as *mut _, len4, len4)
} }
} }
} }
@ -274,7 +374,7 @@ pub mod component {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
#[link_section = "component-type:example"] #[link_section = "component-type:example"]
#[doc(hidden)] #[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)] #[inline(never)]
#[doc(hidden)] #[doc(hidden)]

View File

@ -1,7 +1,7 @@
#[allow(warnings)] #[allow(warnings)]
mod bindings; 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}; use std::{alloc::Layout, any::TypeId, mem};
@ -42,25 +42,30 @@ struct Component;
impl Guest for Component { impl Guest for Component {
fn on_init() -> Result<u8, ()> { fn on_init() -> Result<u8, ()> {
let comps = &mut [Vec3::new(7.0, 30.0, 18.0),]; let world = EcsWorld::new();
spawn_vec3(&world, Vec3::new(7.0, 30.0, 18.0));
spawn_vec3(&world, Vec3::new(90.30, 65.0, 83.0));
bindings::host_print("Spawned entities");
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::<Vec3>()) };
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()]; let info = &[Vec3::component_info()];
// no fucking clue if this will work, but lets try and it see // no fucking clue if this will work, but lets try and it see
let comps = comps.as_mut_ptr().cast::<u8>(); let comps = comps.as_mut_ptr().cast::<u8>();
let comps = unsafe { Vec::from_raw_parts(comps, mem::size_of::<Vec3>(), 1) }; let comps = unsafe { Vec::from_raw_parts(comps, mem::size_of::<Vec3>(), 1) };
let world = EcsWorld::new(); world.spawn(&comps, info)
let en = world.spawn(&comps, info);
//let en = ecs_world::spawn(&comps, info);
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::<Vec3>()) };
bindings::host_print(&format!("Retrieved vec3: {:?}", fetched_vec));
Ok(0)
}
} }

View File

@ -30,12 +30,18 @@ interface ecs {
type-id: wasm-type-id, // a u128 type-id: wasm-type-id, // a u128
} }
resource ecs-dynamic-view {
constructor(wrld: borrow<ecs-world>, component-infos: list<component-info>);
next: func() -> option<list<u8>>;
}
resource ecs-world { resource ecs-world {
constructor(); constructor();
// expects components to be tightly packed in the same order of component-infos // expects components to be tightly packed in the same order of component-infos
spawn: func(components: list<u8>, component-infos: list<component-info>) -> entity; spawn: func(components: list<u8>, component-infos: list<component-info>) -> entity;
view: func(component-infos: list<component-info>) -> list<u8>; view: func(component-infos: list<component-info>) -> ecs-dynamic-view;
} }
} }