From 27c8f936119c5df2451b2455c169271a4ec77b27 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sun, 14 Apr 2024 19:34:07 -0400 Subject: [PATCH] create a 'common-api' crate to make it easier to work with the ecs world --- Cargo.lock | 175 ++++++++++++++++++++-- Cargo.toml | 4 +- common-api/Cargo.toml | 14 ++ common-api/src/lib.rs | 162 ++++++++++++++++++++ common-api/wit/ecs.wit | 36 +++++ common-api/wit/world.wit | 5 + shell.nix | 1 + src/main.rs | 79 +++++----- witguest/Cargo.toml | 6 + witguest/src/bindings.rs | 313 +-------------------------------------- witguest/src/lib.rs | 59 +++----- witguest/wit/world.wit | 40 +---- 12 files changed, 462 insertions(+), 432 deletions(-) create mode 100755 common-api/Cargo.toml create mode 100755 common-api/src/lib.rs create mode 100644 common-api/wit/ecs.wit create mode 100644 common-api/wit/world.wit diff --git a/Cargo.lock b/Cargo.lock index 704be4b..ebb6b6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,6 +136,26 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytemuck" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -241,6 +261,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "common-api" +version = "0.1.0" +dependencies = [ + "bytemuck", + "thiserror", + "wit-bindgen", +] + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -370,7 +399,7 @@ dependencies = [ "itertools", "log", "smallvec", - "wasmparser", + "wasmparser 0.201.0", "wasmtime-types", ] @@ -690,6 +719,9 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] [[package]] name = "hermit-abi" @@ -1297,6 +1329,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spdx" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ef1a0fa1e39ac22972c8db23ff89aea700ab96aa87114e1fb55937a631a0c9" +dependencies = [ + "smallvec", +] + [[package]] name = "sptr" version = "0.3.2" @@ -1499,6 +1540,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + [[package]] name = "unicode-width" version = "0.1.11" @@ -1612,6 +1659,22 @@ dependencies = [ "leb128", ] +[[package]] +name = "wasm-metadata" +version = "0.202.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "094aea3cb90e09f16ee25a4c0e324b3e8c934e7fd838bfa039aef5352f44a917" +dependencies = [ + "anyhow", + "indexmap", + "serde", + "serde_derive", + "serde_json", + "spdx", + "wasm-encoder 0.202.0", + "wasmparser 0.202.0", +] + [[package]] name = "wasmparser" version = "0.201.0" @@ -1623,6 +1686,17 @@ dependencies = [ "semver", ] +[[package]] +name = "wasmparser" +version = "0.202.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6998515d3cf3f8b980ef7c11b29a9b1017d4cf86b99ae93b546992df9931413" +dependencies = [ + "bitflags 2.5.0", + "indexmap", + "semver", +] + [[package]] name = "wasmprinter" version = "0.201.0" @@ -1630,7 +1704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a67e66da702706ba08729a78e3c0079085f6bfcb1a62e4799e97bbf728c2c265" dependencies = [ "anyhow", - "wasmparser", + "wasmparser 0.201.0", ] [[package]] @@ -1663,7 +1737,7 @@ dependencies = [ "serde_json", "target-lexicon", "wasm-encoder 0.201.0", - "wasmparser", + "wasmparser 0.201.0", "wasmtime-cache", "wasmtime-component-macro", "wasmtime-component-util", @@ -1720,7 +1794,7 @@ dependencies = [ "syn", "wasmtime-component-util", "wasmtime-wit-bindgen", - "wit-parser", + "wit-parser 0.201.0", ] [[package]] @@ -1748,7 +1822,7 @@ dependencies = [ "object", "target-lexicon", "thiserror", - "wasmparser", + "wasmparser 0.201.0", "wasmtime-cranelift-shared", "wasmtime-environ", "wasmtime-versioned-export-macros", @@ -1790,7 +1864,7 @@ dependencies = [ "target-lexicon", "thiserror", "wasm-encoder 0.201.0", - "wasmparser", + "wasmparser 0.201.0", "wasmprinter", "wasmtime-component-util", "wasmtime-types", @@ -1880,7 +1954,7 @@ dependencies = [ "serde", "serde_derive", "thiserror", - "wasmparser", + "wasmparser 0.201.0", ] [[package]] @@ -1936,7 +2010,7 @@ dependencies = [ "gimli", "object", "target-lexicon", - "wasmparser", + "wasmparser 0.201.0", "wasmtime-cranelift-shared", "wasmtime-environ", "winch-codegen", @@ -1951,7 +2025,7 @@ dependencies = [ "anyhow", "heck", "indexmap", - "wit-parser", + "wit-parser 0.201.0", ] [[package]] @@ -2067,7 +2141,7 @@ dependencies = [ "regalloc2", "smallvec", "target-lexicon", - "wasmparser", + "wasmparser 0.201.0", "wasmtime-environ", ] @@ -2238,6 +2312,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb4e7653763780be47e38f479e9aa83c768aa6a3b2ed086dc2826fdbbb7e7f5" dependencies = [ "wit-bindgen-rt", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b67e11c950041849a10828c7600ea62a4077c01e8af72e8593253575428f91b" +dependencies = [ + "anyhow", + "wit-parser 0.202.0", ] [[package]] @@ -2249,6 +2334,53 @@ dependencies = [ "bitflags 2.5.0", ] +[[package]] +name = "wit-bindgen-rust" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30acbe8fb708c3a830a33c4cb705df82659bf831b492ec6ca1a17a369cfeeafb" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b1b06eae85feaecdf9f2854f7cac124e00d5a6e5014bfb02eb1ecdeb5f265b9" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.202.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c836b1fd9932de0431c1758d8be08212071b6bba0151f7bac826dbc4312a2a9" +dependencies = [ + "anyhow", + "bitflags 2.5.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder 0.202.0", + "wasm-metadata", + "wasmparser 0.202.0", + "wit-parser 0.202.0", +] + [[package]] name = "wit-parser" version = "0.201.0" @@ -2264,13 +2396,33 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser", + "wasmparser 0.201.0", +] + +[[package]] +name = "wit-parser" +version = "0.202.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744237b488352f4f27bca05a10acb79474415951c450e52ebd0da784c1df2bcc" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.202.0", ] [[package]] name = "witguest" version = "0.1.0" dependencies = [ + "bytemuck", + "common-api", "wit-bindgen", ] @@ -2279,6 +2431,7 @@ name = "wittest" version = "0.1.0" dependencies = [ "async-trait", + "common-api", "lyra-ecs", "slab", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index c4603ce..1435cec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ -workspace = { members = ["witguest"] } +workspace = { members = [ "common-api","witguest"] } [package] name = "wittest" version = "0.1.0" @@ -14,3 +14,5 @@ wasmtime-wasi = "19.0.2" lyra-ecs = { path = "./lyra-engine/lyra-ecs" } slab = "0.4.9" thiserror = "1.0.58" + +common-api = { path = "./common-api" } \ No newline at end of file diff --git a/common-api/Cargo.toml b/common-api/Cargo.toml new file mode 100755 index 0000000..9b6dfc5 --- /dev/null +++ b/common-api/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "common-api" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bytemuck = "1.15.0" +thiserror = "1.0.58" +#bytemuck = "1.15.0" +#wasmtime = "19.0.2" +wit-bindgen = "0.24.0" +#wit-bindgen = { version = "0.24.0", default-features = false, features = ["realloc"] } \ No newline at end of file diff --git a/common-api/src/lib.rs b/common-api/src/lib.rs new file mode 100755 index 0000000..985f7dd --- /dev/null +++ b/common-api/src/lib.rs @@ -0,0 +1,162 @@ +/* pub mod bindings { + wasmtime::component::bindgen!({ + world: "example", + path: "../witguest/wit/world.wit", + //tracing: true, + async: true, + }); +} + +use bindings::{component::witguest::ecs::EcsWorld, *}; */ + +use std::{alloc::Layout, any::TypeId, marker::PhantomData, mem}; + +pub use bytemuck; + +wit_bindgen::generate!({ + world: "api", + path: "wit", +}); + +use lyra::api::ecs::{ComponentInfo, EcsDynamicView, EcsWorld, Entity, WasmTypeId}; + +impl WasmTypeId { + pub fn of() -> Self { + Self { + inner: unsafe { mem::transmute(TypeId::of::()) } + } + } +} + +impl ComponentInfo { + pub fn of() -> Self { + let layout = Layout::new::(); + Self { + size: layout.size() as _, + alignment: layout.align() as _, + type_id: WasmTypeId::of::(), + } + } +} + +#[derive(Debug)] +pub enum ComponentSerializationMethod { + /// Serializes the component into bytes using [`bytemuck::bytes_of`]. + Bytemuck, + /// Serializes the component into bytes using + /// [bincode](https://github.com/bincode-org/bincode). + Bincode +} + +#[derive(Debug, thiserror::Error)] +pub enum ComponentSerializationError { + #[error("{0}")] + Bytemuck(bytemuck::PodCastError), +} + +pub trait Component: Sized + 'static { + const SERIALIZATION: ComponentSerializationMethod; + + fn component_info() -> ComponentInfo; + fn to_bytes(&self) -> Result, ComponentSerializationError>; + fn to_bytes_into(&self, target: &mut Vec) -> Result<(), ComponentSerializationError>; + + fn from_bytes(bytes: &[u8]) -> Result; +} + +#[macro_export] +macro_rules! bytemuck_component_impl { + ($type:ident) => { + impl common_api::Component for $type { + const SERIALIZATION: common_api::ComponentSerializationMethod = common_api::ComponentSerializationMethod::Bytemuck; + + fn component_info() -> common_api::lyra::api::ecs::ComponentInfo { + common_api::lyra::api::ecs::ComponentInfo::of::<$type>() + } + + fn to_bytes(&self) -> Result, common_api::ComponentSerializationError> { + Ok(common_api::bytemuck::bytes_of(self).to_vec()) + } + + fn to_bytes_into(&self, target: &mut Vec) -> Result<(), common_api::ComponentSerializationError> { + let bytes = self.to_bytes()?; + target.extend(bytes.into_iter()); + Ok(()) + } + + fn from_bytes(bytes: &[u8]) -> Result { + common_api::bytemuck::try_from_bytes::(&bytes) + .map_err(|e| common_api::ComponentSerializationError::Bytemuck(e)) + .cloned() + } + } + }; +} + +#[derive(Default)] +pub struct ComponentBundle { + bundle: Vec, + infos: Vec, +} + +impl ComponentBundle { + pub fn new() -> Self { + Self::default() + } + + pub fn push(&mut self, c: C) { + let info = C::component_info(); + self.infos.push(info); + + c.to_bytes_into(&mut self.bundle); + /* self.bundle.reserve(info.size as _); + self.bundle.extend(comp_bytes.into_iter()); */ + + // dont call the destructor on C to avo + //mem::forget(c); + } +} + +pub struct World { + inner: EcsWorld, +} + +impl World { + pub fn new() -> Self { + Self { + inner: EcsWorld::new(), + } + } + + pub fn spawn(&self, components: ComponentBundle) -> Entity { + self.inner.spawn(&components.bundle, &components.infos) + } + + pub fn view(&self, components: &[ComponentInfo]) -> View { + View::from(self.inner.view(components)) + } +} + +pub struct View { + inner: EcsDynamicView, +} + +impl From for View { + fn from(value: EcsDynamicView) -> Self { + Self { + inner: value + } + } +} + +impl View { + pub fn next(&mut self) -> Option { + let row = self.inner.next(); + + if let Some(row) = row { + Some(C::from_bytes(&row).unwrap()) + } else { + None + } + } +} \ No newline at end of file diff --git a/common-api/wit/ecs.wit b/common-api/wit/ecs.wit new file mode 100644 index 0000000..c416c83 --- /dev/null +++ b/common-api/wit/ecs.wit @@ -0,0 +1,36 @@ +package lyra:api; + +interface ecs { + record entity-id { + id: u64, + } + + record entity { + id: entity-id, + generation: u64, + } + + record wasm-type-id { + inner: tuple, + } + + record component-info { + size: u64, + alignment: u64, + 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) -> ecs-dynamic-view; + } +} \ No newline at end of file diff --git a/common-api/wit/world.wit b/common-api/wit/world.wit new file mode 100644 index 0000000..d8262d2 --- /dev/null +++ b/common-api/wit/world.wit @@ -0,0 +1,5 @@ +package lyra:api; + +world api { + import ecs; +} \ No newline at end of file diff --git a/shell.nix b/shell.nix index 69c6e13..46adfa5 100644 --- a/shell.nix +++ b/shell.nix @@ -22,6 +22,7 @@ pkgs.mkShell.override { rust ] ++ (with pkgs; [ cargo-component wasmtime wasm-tools + cargo-expand ]); LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2f0d102..d2a7fde 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,8 @@ use std::alloc::Layout; -use std::any::TypeId; -use std::mem; use std::ptr::NonNull; use async_trait::async_trait; -use component::witguest::ecs::WasmTypeId; -use component::witguest::{ecs as wasm_ecs, math}; +use component::witguest::math; use ecs::query::dynamic::{DynamicViewState, DynamicViewStateIter, QueryDynamicType}; use lyra_ecs::Component; @@ -13,7 +10,7 @@ use lyra_ecs as ecs; use slab::Slab; use thiserror::Error; -use wasmtime_wasi::WasiView; +use wasmtime_wasi::{ResourceTable, WasiCtx, WasiCtxBuilder, WasiView}; use wasmtime::component::Resource as WasmResource; @@ -22,35 +19,18 @@ pub(crate) mod lyra_engine { pub use lyra_ecs as ecs; } -wasmtime::component::bindgen!({ - world: "example", - path: "witguest/wit/world.wit", - //tracing: true, - async: true, -}); +use lyra::api::ecs as wasm_ecs; -impl WasmTypeId { - pub fn of() -> Self { - Self { - inner: unsafe { mem::transmute(TypeId::of::()) }, - } - } -} - -impl Into for WasmTypeId { +impl Into for wasm_ecs::WasmTypeId { fn into(self) -> ecs::DynTypeId { - // SAFETY: the memory layout of (u64, u64) is the same as u128 - ecs::DynTypeId::Unknown(unsafe { mem::transmute(self.inner) }) + ecs::DynTypeId::Unknown(unsafe { std::mem::transmute(self.inner) }) } } impl Into for wasm_ecs::ComponentInfo { fn into(self) -> ecs::ComponentInfo { - ecs::ComponentInfo::new_unknown( - None, - self.type_id, - Layout::from_size_align(self.size as _, self.alignment as _).unwrap(), - ) + let layout = Layout::from_size_align(self.size as _, self.alignment as _).unwrap(); + ecs::ComponentInfo::new_unknown(None, self.type_id, layout) } } @@ -63,6 +43,31 @@ impl From for wasm_ecs::Entity { } } +impl Into for wasm_ecs::Entity { + fn into(self) -> ecs::Entity { + let mut id = ecs::EntityId(self.id.id); + ecs::Entity::new(id, self.generation) + } +} + +wasmtime::component::bindgen!({ + world: "api", + path: "common-api/wit", + //tracing: true, + async: true, +}); + +wasmtime::component::bindgen!({ + world: "example", + path: "witguest/wit", + //tracing: true, + async: true, + + with: { + "lyra:api": lyra::api, + } +}); + #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Component)] struct Vec3 { @@ -88,15 +93,18 @@ unsafe impl Send for DynamicViewEntry {} struct Imports { world_slab: Slab, world_views_slab: Slab, + + ctx: WasiCtx, + table: ResourceTable, } impl WasiView for Imports { fn table(&mut self) -> &mut wasmtime_wasi::ResourceTable { - todo!() + &mut self.table } fn ctx(&mut self) -> &mut wasmtime_wasi::WasiCtx { - todo!() + &mut self.ctx } } @@ -108,8 +116,6 @@ impl ExampleImports for Imports { } } -impl math::Host for Imports {} - #[derive(Error, Debug)] pub enum WasmError { #[error("an invalid '{0}' resource handle was used by the guest")] @@ -181,6 +187,8 @@ impl wasm_ecs::HostEcsWorld for Imports { } } +impl math::Host for Imports {} + #[async_trait] impl wasm_ecs::HostEcsDynamicView for Imports { async fn new( @@ -284,7 +292,10 @@ async fn main() -> wasmtime::Result<()> { let mut linker = wasmtime::component::Linker::new(&engine); wasmtime_wasi::bindings::Imports::add_to_linker(&mut linker, |s| s)?; Example::add_to_linker(&mut linker, |s| s)?; + Api::add_to_linker(&mut linker, |s| s)?; + let mut builder = WasiCtxBuilder::new(); + builder.inherit_stdio(); // memory per instance let mut store = wasmtime::Store::new( &engine, @@ -293,6 +304,8 @@ async fn main() -> wasmtime::Result<()> { // wants another world for some reason. world_slab: Slab::with_capacity(1), world_views_slab: Slab::with_capacity(10), + ctx: builder.build(), + table: ResourceTable::new(), }, ); @@ -303,8 +316,8 @@ async fn main() -> wasmtime::Result<()> { // Instantiate the component println!("creating example"); let (example, _instance) = Example::instantiate_async(&mut store, &component, &linker).await?; - let result = example.call_on_init(&mut store).await?.unwrap(); - println!("Guest returned: {}", result); + example.call_on_init(&mut store).await?.unwrap(); + println!("Guest is done"); Ok(()) } diff --git a/witguest/Cargo.toml b/witguest/Cargo.toml index 8f3b1d3..8a6c42a 100644 --- a/witguest/Cargo.toml +++ b/witguest/Cargo.toml @@ -7,6 +7,9 @@ edition = "2021" [dependencies] wit-bindgen = { version = "0.24.0", default-features = false, features = ["realloc"] } +common-api = { path = "../common-api" } +bytemuck = { version = "1.15.0", features = ["derive"] } +#bytemuck = { version = "1.15.0", features = ["derive"] } [lib] crate-type = ["cdylib"] @@ -15,3 +18,6 @@ crate-type = ["cdylib"] package = "component:witguest" [package.metadata.component.dependencies] + +[package.metadata.component.target.dependencies] +#"lyra:api" = { path = "../common-api/wit" } \ No newline at end of file diff --git a/witguest/src/bindings.rs b/witguest/src/bindings.rs index 59a5963..de75a9b 100644 --- a/witguest/src/bindings.rs +++ b/witguest/src/bindings.rs @@ -45,29 +45,16 @@ const _: () = { wit_bindgen::rt::run_ctors_once(); let result0 = <_GuestImpl as Guest>::on_init(); - let ptr1 = _RET_AREA.0.as_mut_ptr() as i32; - match result0 { - Ok(e) => { { - *((ptr1 + 0) as *mut u8) = (0i32) as u8; - *((ptr1 + 1) as *mut u8) = (wit_bindgen::rt::as_i32(e)) as u8; - } }, - Err(_) => { { - *((ptr1 + 0) as *mut u8) = (1i32) as u8; - } }, - };ptr1 + let result1 = match result0 { + Ok(_) => { 0i32 }, + Err(_) => { 1i32 }, + };result1 } }; use super::Component as _GuestImpl; pub trait Guest { - fn on_init() -> Result; + fn on_init() -> Result<(),()>; } - -#[allow(unused_imports)] -use wit_bindgen::rt::{alloc, vec::Vec, string::String}; - -#[repr(align(1))] -struct _RetArea([u8; 2]); -static mut _RET_AREA: _RetArea = _RetArea([0; 2]); pub mod component { pub mod witguest { @@ -80,301 +67,13 @@ pub mod component { } - - #[allow(clippy::all)] - pub mod ecs { - #[used] - #[doc(hidden)] - #[cfg(target_arch = "wasm32")] - static __FORCE_SECTION_REF: fn() = super::super::super::__link_section; - /// use math.{vec3}; - #[repr(C)] - #[derive(Clone, Copy)] - pub struct EntityId { - pub id: u64, - } - impl ::core::fmt::Debug for EntityId { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - f.debug_struct("EntityId").field("id", &self.id).finish() - } - } - #[repr(C)] - #[derive(Clone, Copy)] - pub struct Entity { - pub id: EntityId, - pub generation: u64, - } - impl ::core::fmt::Debug for Entity { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - f.debug_struct("Entity").field("id", &self.id).field("generation", &self.generation).finish() - } - } - #[repr(C)] - #[derive(Clone, Copy)] - pub struct WasmTypeId { - pub inner: (u64,u64,), - } - impl ::core::fmt::Debug for WasmTypeId { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - f.debug_struct("WasmTypeId").field("inner", &self.inner).finish() - } - } - #[repr(C)] - #[derive(Clone, Copy)] - pub struct ComponentInfo { - pub size: u64, - pub alignment: u64, - pub type_id: WasmTypeId, - } - impl ::core::fmt::Debug for ComponentInfo { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - f.debug_struct("ComponentInfo").field("size", &self.size).field("alignment", &self.alignment).field("type-id", &self.type_id).finish() - } - } - - #[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{ - handle: wit_bindgen::rt::Resource, - } - - impl EcsWorld{ - #[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 EcsWorld{ - #[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-world"] - fn drop(_: u32); - } - - drop(_handle); - } - } - } - - 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{ - - #[allow(unused_imports)] - use wit_bindgen::rt::{alloc, vec::Vec, string::String}; - unsafe { - - #[cfg(target_arch = "wasm32")] - #[link(wasm_import_module = "component:witguest/ecs")] - extern "C" { - #[link_name = "[constructor]ecs-world"] - fn wit_import() -> i32; - } - - #[cfg(not(target_arch = "wasm32"))] - fn wit_import() -> i32{ unreachable!() } - let ret = wit_import(); - EcsWorld::from_handle(ret as u32) - } - } - } - 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)] - use wit_bindgen::rt::{alloc, vec::Vec, string::String}; - unsafe { - - #[repr(align(8))] - struct RetArea([u8; 16]); - let mut ret_area = ::core::mem::MaybeUninit::::uninit(); - let vec0 = components; - let ptr0 = vec0.as_ptr() as i32; - let len0 = vec0.len() as i32; - let vec1 = component_infos; - let ptr1 = vec1.as_ptr() as i32; - let len1 = vec1.len() as i32; - let ptr2 = 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.spawn"] - fn wit_import(_: i32, _: i32, _: i32, _: i32, _: i32, _: i32, ); - } - - #[cfg(not(target_arch = "wasm32"))] - fn wit_import(_: i32, _: i32, _: i32, _: i32, _: i32, _: i32, ){ unreachable!() } - wit_import((self).handle() as i32, ptr0, len0, ptr1, len1, ptr2); - let l3 = *((ptr2 + 0) as *const i64); - let l4 = *((ptr2 + 8) as *const i64); - Entity{ - id: EntityId{ - id: l3 as u64, - }, - generation: l4 as u64, - } - } - } - } - impl EcsWorld { - #[allow(unused_unsafe, clippy::all)] - pub fn view(&self,component_infos: &[ComponentInfo],) -> EcsDynamicView{ - - #[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 = "[method]ecs-world.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((self).handle() as i32, ptr0, len0); - EcsDynamicView::from_handle(ret as u32) - } - } - } - - } - } } #[cfg(target_arch = "wasm32")] #[link_section = "component-type:example"] #[doc(hidden)] -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]; +pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 261] = [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, 136, 1, 1, 65, 2, 1, 65, 7, 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, 64, 1, 3, 109, 115, 103, 115, 1, 0, 3, 0, 10, 104, 111, 115, 116, 45, 112, 114, 105, 110, 116, 1, 1, 1, 106, 0, 0, 1, 64, 0, 0, 2, 4, 0, 7, 111, 110, 45, 105, 110, 105, 116, 1, 3, 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 058bf0b..0a419ed 100644 --- a/witguest/src/lib.rs +++ b/witguest/src/lib.rs @@ -1,20 +1,14 @@ #[allow(warnings)] mod bindings; -use bindings::{component::witguest::ecs::{ComponentInfo, EcsWorld, Entity, WasmTypeId}, Guest}; +use bindings::Guest; +//use bindings::{component::witguest::ecs::{ComponentInfo, EcsWorld, Entity, WasmTypeId}, Guest}; +use common_api::{bytemuck_component_impl, Component as EcsComponent, ComponentBundle, World}; use std::{alloc::Layout, any::TypeId, mem}; -impl WasmTypeId { - pub fn of() -> Self { - Self { - inner: unsafe { mem::transmute(TypeId::of::()) } - } - } -} - #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)] struct Vec3 { x: f32, y: f32, @@ -27,45 +21,28 @@ impl Vec3 { x, y, z } } - - pub fn component_info() -> ComponentInfo { - let layout = Layout::new::(); - ComponentInfo { - size: layout.size() as u64, - alignment: layout.align() as u64, - type_id: WasmTypeId::of::(), - } - } } +bytemuck_component_impl!(Vec3); + struct Component; impl Guest for Component { - fn on_init() -> Result { - 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)); + fn on_init() -> Result<(), ()> { + let world = World::new(); - bindings::host_print("Spawned entities"); + let mut bundle = ComponentBundle::new(); + bundle.push(Vec3::new(7.0, 30.0, 18.0)); + let en = world.spawn(bundle); - 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)); + println!("guest spawned {:?}", en); + + + let mut view = world.view(&[Vec3::component_info()]); + while let Some(c) = view.next::() { + println!("Retrieved vec3: {:?}", c); } - Ok(0) + Ok(()) } -} - -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 18be241..a31edd3 100644 --- a/witguest/wit/world.wit +++ b/witguest/wit/world.wit @@ -8,48 +8,10 @@ interface math { } } -interface ecs { - //use math.{vec3}; - - record entity-id { - id: u64, - } - - record entity { - id: entity-id, - generation: u64, - } - - record wasm-type-id { - inner: tuple, - } - - record component-info { - size: u64, - alignment: u64, - 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) -> ecs-dynamic-view; - } -} - /// An example world for the component to target. world example { import math; - import ecs; import host-print: func(msg: string); - export on-init: func() -> result; + export on-init: func() -> result; }