change how bindings are generated, make it easier to call functions on the guest
This commit is contained in:
parent
f6933de559
commit
4deed47b3d
|
@ -1 +1,2 @@
|
||||||
/target
|
/target
|
||||||
|
wasi_snapshot_preview1.reactor.wasm
|
|
@ -46,9 +46,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.82"
|
version = "1.0.86"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
|
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "api-derive"
|
name = "api-derive"
|
||||||
|
@ -2470,6 +2470,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"common-api",
|
"common-api",
|
||||||
|
"wit-bindgen",
|
||||||
"wit-bindgen-rt",
|
"wit-bindgen-rt",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2477,6 +2478,7 @@ dependencies = [
|
||||||
name = "wittest"
|
name = "wittest"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"common-api",
|
"common-api",
|
||||||
"lyra-ecs",
|
"lyra-ecs",
|
||||||
|
|
|
@ -17,3 +17,4 @@ slab = "0.4.9"
|
||||||
thiserror = "1.0.58"
|
thiserror = "1.0.58"
|
||||||
|
|
||||||
common-api = { path = "./common-api" }
|
common-api = { path = "./common-api" }
|
||||||
|
anyhow = "1.0.86"
|
||||||
|
|
|
@ -19,8 +19,8 @@ Install [`cargo-component`](https://github.com/bytecodealliance/cargo-component)
|
||||||
cargo install wasm-tools
|
cargo install wasm-tools
|
||||||
```
|
```
|
||||||
|
|
||||||
Build the `witguest` project:
|
Download [`wasi_snapshot_preview1.reactor.wasm`](https://github.com/bytecodealliance/wasmtime/releases/download/v17.0.0/wasi_snapshot_preview1.reactor.wasm) in the `witguest` folder. Build the `witguest` project then use an adapter to convert the WASM module to a component:
|
||||||
```
|
```
|
||||||
cd witguest
|
cd witguest
|
||||||
cargo component build
|
cargo build --target wasm32-wasip1 && wasm-tools component new ../target/wasm32-wasip1/debug/witguest.wasm -o ../target/wasm32-wasip1/debug/witguest-component.wasm --adapt ../wasi_snapshot_preview1.reactor.wasm
|
||||||
```
|
```
|
|
@ -13,3 +13,8 @@ thiserror = "1.0.58"
|
||||||
wit-bindgen = "0.28.0"
|
wit-bindgen = "0.28.0"
|
||||||
#wit-bindgen = { version = "0.24.0", default-features = false, features = ["realloc"] }
|
#wit-bindgen = { version = "0.24.0", default-features = false, features = ["realloc"] }
|
||||||
api-derive = { path = "./api-derive" }
|
api-derive = { path = "./api-derive" }
|
||||||
|
|
||||||
|
[package.metadata.component]
|
||||||
|
package = "lyra:api"
|
||||||
|
|
||||||
|
[package.metadata.component.dependencies]
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{any::TypeId, marker::PhantomData, mem};
|
use std::{any::TypeId, marker::PhantomData, mem, ops::Deref};
|
||||||
|
|
||||||
pub use bytemuck;
|
pub use bytemuck;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ pub use api_derive as macros;
|
||||||
|
|
||||||
pub mod bindings {
|
pub mod bindings {
|
||||||
wit_bindgen::generate!({
|
wit_bindgen::generate!({
|
||||||
world: "api",
|
world: "imports",
|
||||||
path: "wit",
|
path: "wit",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -31,14 +31,46 @@ impl WasmTypeId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct World {
|
enum OwnedBorrow<'a, T> {
|
||||||
inner: EcsWorld,
|
Borrowed(&'a T),
|
||||||
|
Owned(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl World {
|
impl<'a, T> Deref for OwnedBorrow<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
OwnedBorrow::Borrowed(v) => *v,
|
||||||
|
OwnedBorrow::Owned(v) => &v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct World<'a> {
|
||||||
|
inner: OwnedBorrow<'a, EcsWorld>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<EcsWorld> for World<'a> {
|
||||||
|
fn from(value: EcsWorld) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: OwnedBorrow::Owned(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a EcsWorld> for World<'a> {
|
||||||
|
fn from(value: &'a EcsWorld) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: OwnedBorrow::Borrowed(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> World<'a> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: EcsWorld::new(),
|
inner: OwnedBorrow::Owned(EcsWorld::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,5 +56,7 @@ interface ecs {
|
||||||
///
|
///
|
||||||
/// Returns: an iterator that returns the byte buffers of each row.
|
/// Returns: an iterator that returns the byte buffers of each row.
|
||||||
view: func(component-infos: list<component-info>) -> ecs-dynamic-view;
|
view: func(component-infos: list<component-info>) -> ecs-dynamic-view;
|
||||||
|
|
||||||
|
//with_system: func(stage: string, component-infos: list<component-info>, system: func(components: list<u8>));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
package lyra:api;
|
package lyra:api;
|
||||||
|
|
||||||
world api {
|
world imports {
|
||||||
import ecs;
|
import ecs;
|
||||||
}
|
}
|
123
src/main.rs
123
src/main.rs
|
@ -1,10 +1,12 @@
|
||||||
use std::alloc::Layout;
|
use std::alloc::Layout;
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Context};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use component::witguest::math;
|
use component::witguest::math;
|
||||||
use ecs::query::dynamic::{DynamicViewState, DynamicViewStateIter, QueryDynamicType};
|
use ecs::query::dynamic::{DynamicViewState, DynamicViewStateIter, QueryDynamicType};
|
||||||
use lyra_ecs::Component;
|
use lyra_ecs::{Component, World};
|
||||||
|
|
||||||
use lyra_ecs as ecs;
|
use lyra_ecs as ecs;
|
||||||
|
|
||||||
|
@ -12,13 +14,57 @@ use slab::Slab;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasmtime_wasi::{ResourceTable, WasiCtx, WasiCtxBuilder, WasiView};
|
use wasmtime_wasi::{ResourceTable, WasiCtx, WasiCtxBuilder, WasiView};
|
||||||
|
|
||||||
use wasmtime::component::Resource as WasmResource;
|
use wasmtime::component::{Resource as WasmResource, ResourceAny};
|
||||||
|
|
||||||
|
use wasmtime::component::Val as ComponentVal;
|
||||||
|
|
||||||
#[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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* mod bindings {
|
||||||
|
wasmtime::component::bindgen!({
|
||||||
|
world: "imports",
|
||||||
|
path: "common-api/wit",
|
||||||
|
//tracing: true,
|
||||||
|
async: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
mod component {
|
||||||
|
wasmtime::component::bindgen!({
|
||||||
|
world: "example",
|
||||||
|
path: "witguest/wit",
|
||||||
|
//tracing: true,
|
||||||
|
async: true,
|
||||||
|
|
||||||
|
with: {
|
||||||
|
"lyra:api": super::lyra::api,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use bindings::lyra::api::ecs as wasm_ecs; */
|
||||||
|
|
||||||
|
/* wasmtime::component::bindgen!({
|
||||||
|
world: "imports",
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
use lyra::api::ecs as wasm_ecs;
|
use lyra::api::ecs as wasm_ecs;
|
||||||
|
|
||||||
impl Into<ecs::DynTypeId> for wasm_ecs::WasmTypeId {
|
impl Into<ecs::DynTypeId> for wasm_ecs::WasmTypeId {
|
||||||
|
@ -50,24 +96,6 @@ impl Into<ecs::Entity> for wasm_ecs::Entity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Component)]
|
#[derive(Debug, Clone, Copy, PartialEq, Component)]
|
||||||
struct Vec3 {
|
struct Vec3 {
|
||||||
|
@ -220,10 +248,7 @@ impl wasm_ecs::HostEcsDynamicView for Imports {
|
||||||
WasmResource::new_own(view_index as _)
|
WasmResource::new_own(view_index as _)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn next(
|
async fn next(&mut self, view: WasmResource<wasm_ecs::EcsDynamicView>) -> Option<Vec<u8>> {
|
||||||
&mut self,
|
|
||||||
view: WasmResource<wasm_ecs::EcsDynamicView>,
|
|
||||||
) -> Option<Vec<u8>> {
|
|
||||||
let view_entry = self.world_views_slab.get_mut(view.rep() as _).unwrap();
|
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 world_entry = self.world_slab.get(view_entry.world_index).unwrap();
|
||||||
let view = &mut view_entry.view;
|
let view = &mut view_entry.view;
|
||||||
|
@ -296,7 +321,8 @@ async fn main() -> wasmtime::Result<()> {
|
||||||
//wasmtime_wasi::bindings::Imports::add_to_linker(&mut linker, |s| s)?;
|
//wasmtime_wasi::bindings::Imports::add_to_linker(&mut linker, |s| s)?;
|
||||||
wasmtime_wasi::add_to_linker_async(&mut linker)?;
|
wasmtime_wasi::add_to_linker_async(&mut linker)?;
|
||||||
Example::add_to_linker(&mut linker, |s| s)?;
|
Example::add_to_linker(&mut linker, |s| s)?;
|
||||||
Api::add_to_linker(&mut linker, |s| s)?;
|
//lyra::api::ecs::add_to_linker(&mut linker, |s| s)?;
|
||||||
|
//Api::add_to_linker(&mut linker, |s| s)?;
|
||||||
|
|
||||||
let mut builder = WasiCtxBuilder::new();
|
let mut builder = WasiCtxBuilder::new();
|
||||||
builder.inherit_stdio();
|
builder.inherit_stdio();
|
||||||
|
@ -314,14 +340,53 @@ async fn main() -> wasmtime::Result<()> {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Load the component from disk
|
// Load the component from disk
|
||||||
let bytes = std::fs::read("target/wasm32-wasip1/debug/witguest.wasm")?;
|
let bytes = std::fs::read("target/wasm32-wasip1/debug/witguest-component.wasm")?;
|
||||||
let component = wasmtime::component::Component::new(&engine, bytes)?;
|
let component = wasmtime::component::Component::new(&engine, bytes)?;
|
||||||
|
|
||||||
|
let (script_en, (world_res_a, world_res_b)) = {
|
||||||
|
let mut world = World::new();
|
||||||
|
let script_en = world.spawn(());
|
||||||
|
|
||||||
|
let data = store.data_mut();
|
||||||
|
let world_idx = data.world_slab.insert(WorldEntry {
|
||||||
|
world,
|
||||||
|
views: Slab::with_capacity(10),
|
||||||
|
});
|
||||||
|
let resa = WasmResource::<EcsWorld>::new_borrow(world_idx as _);
|
||||||
|
let resb = WasmResource::<EcsWorld>::new_borrow(world_idx as _);
|
||||||
|
|
||||||
|
(script_en, (resa, resb))
|
||||||
|
};
|
||||||
|
|
||||||
// Instantiate the component
|
// Instantiate the component
|
||||||
println!("creating example");
|
println!("creating example component");
|
||||||
let example = Example::instantiate_async(&mut store, &component, &linker).await?;
|
let instance = linker.instantiate_async(&mut store, &component).await?;
|
||||||
example.call_on_init(&mut store).await?.unwrap();
|
|
||||||
|
call_script_stage_async(&mut store, &instance, "init", world_res_a, script_en.into()).await?;
|
||||||
|
call_script_stage_async(&mut store, &instance, "update", world_res_b, script_en.into()).await?;
|
||||||
|
|
||||||
println!("Guest is done");
|
println!("Guest is done");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn call_script_stage_async(mut store: &mut wasmtime::Store<Imports>, instance: &wasmtime::component::Instance, stage_name: &str, world_res: wasmtime::component::Resource<EcsWorld>, script_entity: Entity) -> anyhow::Result<()> {
|
||||||
|
let func_name = format!("on-{}", stage_name);
|
||||||
|
let func = instance
|
||||||
|
.get_func(&mut store, &func_name)
|
||||||
|
.expect("Could not find on_init");
|
||||||
|
|
||||||
|
let typed_func = unsafe {
|
||||||
|
wasmtime::component::TypedFunc::<
|
||||||
|
(wasmtime::component::Resource<EcsWorld>, Entity),
|
||||||
|
(Result<(), ()>,),
|
||||||
|
>::new_unchecked(func)
|
||||||
|
};
|
||||||
|
|
||||||
|
let (ret,) = typed_func.call_async(&mut store, (world_res, script_entity.into())).await
|
||||||
|
.with_context(|| format!("failed to call guest function {func_name}"))?;
|
||||||
|
typed_func.post_return_async(&mut store).await
|
||||||
|
.with_context(|| format!("failed to call post-return function of guest after calling {func_name}"))?;
|
||||||
|
|
||||||
|
ret.map_err(|_| anyhow!("unknown error returned from guest when calling function {func_name}"))
|
||||||
|
}
|
||||||
|
|
|
@ -3,10 +3,11 @@ name = "witguest"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
#build = "build.rs"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
#wit-bindgen = { version = "0.28.0", default-features = false, features = ["realloc"] }
|
wit-bindgen = { version = "0.28.0", default-features = false, features = ["realloc"] }
|
||||||
wit-bindgen-rt = { version = "0.28.0", features = ["bitflags"] }
|
wit-bindgen-rt = { version = "0.28.0", features = ["bitflags"] }
|
||||||
common-api = { path = "../common-api" }
|
common-api = { path = "../common-api" }
|
||||||
bytemuck = { version = "1.15.0", features = ["derive"] }
|
bytemuck = { version = "1.15.0", features = ["derive"] }
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
use std::{fs, io, path::Path};
|
||||||
|
|
||||||
|
|
||||||
|
// Example custom build script.
|
||||||
|
fn main() {
|
||||||
|
// Tell Cargo that if the given file changes, to rerun this build script.
|
||||||
|
println!("cargo::rerun-if-changed=../common-api/wit/");
|
||||||
|
|
||||||
|
fs::remove_dir_all("./wit/deps/lyraapi").unwrap();
|
||||||
|
copy_dir_all("../common-api/wit", "./wit/deps/lyraapi").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
|
||||||
|
fs::create_dir_all(&dst)?;
|
||||||
|
|
||||||
|
for entry in fs::read_dir(src)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let ty = entry.file_type()?;
|
||||||
|
if ty.is_dir() {
|
||||||
|
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
|
||||||
|
} else {
|
||||||
|
fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,118 +0,0 @@
|
||||||
// Generated by `wit-bindgen` 0.25.0. DO NOT EDIT!
|
|
||||||
// Options used:
|
|
||||||
#[allow(unused_unsafe, clippy::all)]
|
|
||||||
pub fn host_print(msg: &str) {
|
|
||||||
unsafe {
|
|
||||||
let vec0 = msg;
|
|
||||||
let ptr0 = vec0.as_ptr().cast::<u8>();
|
|
||||||
let len0 = vec0.len();
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
#[link(wasm_import_module = "$root")]
|
|
||||||
extern "C" {
|
|
||||||
#[link_name = "host-print"]
|
|
||||||
fn wit_import(_: *mut u8, _: usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
fn wit_import(_: *mut u8, _: usize) {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
wit_import(ptr0.cast_mut(), len0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub unsafe fn _export_on_init_cabi<T: Guest>() -> i32 {
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
_rt::run_ctors_once();
|
|
||||||
let result0 = T::on_init();
|
|
||||||
let result1 = match result0 {
|
|
||||||
Ok(_) => 0i32,
|
|
||||||
Err(_) => 1i32,
|
|
||||||
};
|
|
||||||
result1
|
|
||||||
}
|
|
||||||
pub trait Guest {
|
|
||||||
fn on_init() -> Result<(), ()>;
|
|
||||||
}
|
|
||||||
#[doc(hidden)]
|
|
||||||
|
|
||||||
macro_rules! __export_world_example_cabi{
|
|
||||||
($ty:ident with_types_in $($path_to_types:tt)*) => (const _: () = {
|
|
||||||
|
|
||||||
#[export_name = "on-init"]
|
|
||||||
unsafe extern "C" fn export_on_init() -> i32 {
|
|
||||||
$($path_to_types)*::_export_on_init_cabi::<$ty>()
|
|
||||||
}
|
|
||||||
};);
|
|
||||||
}
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub(crate) use __export_world_example_cabi;
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub mod component {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub mod witguest {
|
|
||||||
#[allow(dead_code, clippy::all)]
|
|
||||||
pub mod math {
|
|
||||||
#[used]
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
static __FORCE_SECTION_REF: fn() =
|
|
||||||
super::super::super::__link_custom_section_describing_imports;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mod _rt {
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
pub fn run_ctors_once() {
|
|
||||||
wit_bindgen_rt::run_ctors_once();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates `#[no_mangle]` functions to export the specified type as the
|
|
||||||
/// root implementation of all generated traits.
|
|
||||||
///
|
|
||||||
/// For more information see the documentation of `wit_bindgen::generate!`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # macro_rules! export{ ($($t:tt)*) => (); }
|
|
||||||
/// # trait Guest {}
|
|
||||||
/// struct MyType;
|
|
||||||
///
|
|
||||||
/// impl Guest for MyType {
|
|
||||||
/// // ...
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// export!(MyType);
|
|
||||||
/// ```
|
|
||||||
#[allow(unused_macros)]
|
|
||||||
#[doc(hidden)]
|
|
||||||
|
|
||||||
macro_rules! __export_example_impl {
|
|
||||||
($ty:ident) => (self::export!($ty with_types_in self););
|
|
||||||
($ty:ident with_types_in $($path_to_types_root:tt)*) => (
|
|
||||||
$($path_to_types_root)*::__export_world_example_cabi!($ty with_types_in $($path_to_types_root)*);
|
|
||||||
)
|
|
||||||
}
|
|
||||||
#[doc(inline)]
|
|
||||||
pub(crate) use __export_example_impl as export;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
#[link_section = "component-type:wit-bindgen:0.25.0:example:encoded world"]
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 262] = *b"\
|
|
||||||
\0asm\x0d\0\x01\0\0\x19\x16wit-component-encoding\x04\0\x07\x88\x01\x01A\x02\x01\
|
|
||||||
A\x07\x01B\x02\x01r\x03\x01xv\x01yv\x01zv\x04\0\x04vec3\x03\0\0\x03\x01\x17compo\
|
|
||||||
nent:witguest/math\x05\0\x01@\x01\x03msgs\x01\0\x03\0\x0ahost-print\x01\x01\x01j\
|
|
||||||
\0\0\x01@\0\0\x02\x04\0\x07on-init\x01\x03\x04\x01\x1acomponent:witguest/example\
|
|
||||||
\x04\0\x0b\x0d\x01\0\x07example\x03\0\0\0G\x09producers\x01\x0cprocessed-by\x02\x0d\
|
|
||||||
wit-component\x070.208.1\x10wit-bindgen-rust\x060.25.0";
|
|
||||||
|
|
||||||
#[inline(never)]
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
pub fn __link_custom_section_describing_imports() {
|
|
||||||
wit_bindgen_rt::maybe_link_cabi_realloc();
|
|
||||||
}
|
|
|
@ -1,18 +1,28 @@
|
||||||
#[allow(warnings)]
|
use common_api::{math::{Vec3, Vec4}, World};
|
||||||
mod bindings;
|
|
||||||
|
|
||||||
use bindings::Guest;
|
wit_bindgen::generate!({
|
||||||
use common_api::{World, math::{Vec3, Vec4}};
|
world: "example",
|
||||||
|
|
||||||
|
with: {
|
||||||
|
"lyra:api/ecs": common_api::bindings::lyra::api::ecs,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
struct Component;
|
struct Component;
|
||||||
|
|
||||||
impl Guest for Component {
|
impl Guest for Component {
|
||||||
fn on_init() -> Result<(), ()> {
|
fn on_init(world: &EcsWorld, _owning_entity: Entity) -> Result<(), ()> {
|
||||||
let world = World::new();
|
let world = World::from(world);
|
||||||
let en = world.spawn((Vec3::new(7.0, 30.0, 18.0), Vec4::new(10.0, 332.35, 329.0, 95.0)));
|
let en = world.spawn((Vec3::new(7.0, 30.0, 18.0), Vec4::new(10.0, 332.35, 329.0, 95.0)));
|
||||||
|
|
||||||
println!("guest spawned {:?}", en);
|
println!("guest spawned {:?}", en);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_update(world: &EcsWorld, _owning_entity: Entity) -> Result<(), ()> {
|
||||||
|
let world = World::from(world);
|
||||||
|
|
||||||
let view = world.view::<(Vec3, Vec4)>();
|
let view = world.view::<(Vec3, Vec4)>();
|
||||||
for pos in view {
|
for pos in view {
|
||||||
let (p3, p4) = pos.unwrap();
|
let (p3, p4) = pos.unwrap();
|
||||||
|
@ -24,4 +34,4 @@ impl Guest for Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bindings::export!(Component with_types_in bindings);
|
export!(Component);
|
|
@ -0,0 +1,62 @@
|
||||||
|
package lyra:api;
|
||||||
|
|
||||||
|
interface ecs {
|
||||||
|
record entity-id {
|
||||||
|
id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
record entity {
|
||||||
|
id: entity-id,
|
||||||
|
generation: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
record wasm-type-id {
|
||||||
|
// represents a u128, can be converted into that with mem::transmute
|
||||||
|
inner: tuple<u64, u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
record component-info {
|
||||||
|
host-name: option<string>,
|
||||||
|
/// The size of the component in memory.
|
||||||
|
size: u64,
|
||||||
|
/// The alignment of the component in memory.
|
||||||
|
alignment: u64,
|
||||||
|
/// The type id of the component.
|
||||||
|
///
|
||||||
|
/// This must be unique between component types since its used to identify the components
|
||||||
|
/// in spawning and querying.
|
||||||
|
type-id: wasm-type-id,
|
||||||
|
}
|
||||||
|
|
||||||
|
resource ecs-dynamic-view {
|
||||||
|
constructor(wrld: borrow<ecs-world>, component-infos: list<component-info>);
|
||||||
|
|
||||||
|
/// Get the bytes of the next row in the view.
|
||||||
|
///
|
||||||
|
/// A row contains multiple component serialized as bytes. The buffer is tighly packed.
|
||||||
|
next: func() -> option<list<u8>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
resource ecs-world {
|
||||||
|
constructor();
|
||||||
|
|
||||||
|
/// Spawn an entity.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// * `components`: A tightly packed byte buffer containing the components to spawn
|
||||||
|
/// with the entity. This expects the components in the same order of `component-infos`.
|
||||||
|
/// * `component-infos`: A list of `component-infos` uses to identify the components
|
||||||
|
/// and specify the layouts of them.
|
||||||
|
spawn: func(components: list<u8>, component-infos: list<component-info>) -> entity;
|
||||||
|
|
||||||
|
/// Query for a list of entities and their components.
|
||||||
|
///
|
||||||
|
/// Parameters:
|
||||||
|
/// * `component-infos`: The `component-info`'s of the components that you are querying.
|
||||||
|
///
|
||||||
|
/// Returns: an iterator that returns the byte buffers of each row.
|
||||||
|
view: func(component-infos: list<component-info>) -> ecs-dynamic-view;
|
||||||
|
|
||||||
|
//with_system: func(stage: string, component-infos: list<component-info>, system: func(components: list<u8>));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package lyra:api;
|
||||||
|
|
||||||
|
world imports {
|
||||||
|
import ecs;
|
||||||
|
}
|
|
@ -11,7 +11,10 @@ interface math {
|
||||||
/// An example world for the component to target.
|
/// An example world for the component to target.
|
||||||
world example {
|
world example {
|
||||||
import math;
|
import math;
|
||||||
|
use lyra:api/ecs.{ecs-world, entity};
|
||||||
|
|
||||||
import host-print: func(msg: string);
|
import host-print: func(msg: string);
|
||||||
export on-init: func() -> result;
|
|
||||||
|
export on-init: func(game-world: borrow<ecs-world>, owning-entity: entity) -> result;
|
||||||
|
export on-update: func(game-world: borrow<ecs-world>, owning-entity: entity) -> result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue