use std::ptr::NonNull;
use anyhow::Result;
use bevy_ecs::{prelude::*, reflect::AppTypeRegistry, world::FilteredEntityMut};
use wasmtime::component::ResourceAny;
use wasmtime_wasi::ResourceTable;
use crate::{
access::ModAccess,
cleanup::InsertDespawnComponent,
component::WasmComponentRegistry,
engine::Engine,
host::WasmHost,
methods::FunctionIndex,
query::{Queries, QueryResolver},
send_sync_ptr::SendSyncPtr,
serialize::CodecResource,
system::AddSystems,
};
pub(crate) type Store = wasmtime::Store<WasmHost>;
pub(crate) struct Runner {
store: Store,
}
impl Runner {
pub(crate) fn new(engine: &Engine) -> Self {
let host = WasmHost::new();
let store = Store::new(engine.inner(), host);
Self { store }
}
pub fn table(&mut self) -> &mut ResourceTable {
self.store.data_mut().table()
}
pub(crate) fn new_resource<T>(&mut self, entry: T) -> Result<ResourceAny>
where
T: Send + 'static,
{
let resource = self.table().push(entry)?;
resource.try_into_resource_any(&mut self.store)
}
pub(crate) fn use_store<'a, 'b, 'c, 'd, 'e, 'f, 'g, F, R>(
&mut self,
config: Config<'a, 'b, 'c, 'd, 'e, 'f, 'g>,
mut f: F,
) -> R
where
F: FnMut(&mut Store) -> R,
{
self.store.data_mut().set_data(Data(match config {
Config::Setup(ConfigSetup {
world,
add_systems: systems,
}) => Inner::Setup {
world: SendSyncPtr::new(world.into()),
add_systems: SendSyncPtr::new(systems.into()),
},
Config::RunSystem(ConfigRunSystem {
commands,
type_registry,
codec,
wasm_registry,
function_index,
queries,
query_resolver,
access,
insert_despawn_component,
}) => Inner::RunSystem {
commands: SendSyncPtr::new(NonNull::from_mut(commands).cast()),
type_registry: SendSyncPtr::new(NonNull::from_ref(type_registry)),
codec: SendSyncPtr::new(NonNull::from_ref(codec)),
wasm_registry: SendSyncPtr::new(NonNull::from_ref(wasm_registry)),
function_index: SendSyncPtr::new(NonNull::from_ref(function_index)),
queries: SendSyncPtr::new(NonNull::from_ref(queries).cast()),
query_resolver: SendSyncPtr::new(NonNull::from_ref(query_resolver)),
access,
insert_despawn_component,
},
}));
let ret = f(&mut self.store);
self.store.data_mut().clear();
ret
}
}
pub(crate) struct Data(Inner);
enum Inner {
Uninitialized,
Setup {
world: SendSyncPtr<World>,
add_systems: SendSyncPtr<AddSystems>,
},
RunSystem {
commands: SendSyncPtr<Commands<'static, 'static>>,
type_registry: SendSyncPtr<AppTypeRegistry>,
codec: SendSyncPtr<CodecResource>,
wasm_registry: SendSyncPtr<WasmComponentRegistry>,
function_index: SendSyncPtr<FunctionIndex>,
queries: SendSyncPtr<Queries<'static, 'static>>,
query_resolver: SendSyncPtr<QueryResolver>,
access: ModAccess,
insert_despawn_component: InsertDespawnComponent,
},
}
impl Data {
pub(crate) fn uninitialized() -> Self {
Self(Inner::Uninitialized)
}
pub(crate) fn access<'a>(&'a mut self, table: &'a mut ResourceTable) -> Option<State<'a>> {
match &mut self.0 {
Inner::Setup {
world,
add_systems: systems,
} => Some(State::Setup {
world: unsafe { world.as_mut() },
table,
add_systems: unsafe { systems.as_mut() },
}),
Inner::RunSystem {
commands,
type_registry,
codec,
wasm_registry,
function_index,
queries,
query_resolver,
access,
insert_despawn_component,
} =>
unsafe {
Some(State::RunSystem {
commands: commands.cast().as_mut(),
type_registry: type_registry.as_ref(),
codec: codec.as_ref(),
wasm_registry: wasm_registry.as_ref(),
function_index: function_index.as_ref(),
queries: queries.cast().as_mut(),
query_resolver: query_resolver.as_ref(),
insert_despawn_component,
access,
table,
})
},
Inner::Uninitialized => None,
}
}
}
pub(crate) enum State<'a> {
Setup {
world: &'a mut World,
table: &'a mut ResourceTable,
add_systems: &'a mut AddSystems,
},
RunSystem {
table: &'a mut ResourceTable,
commands: &'a mut Commands<'a, 'a>,
type_registry: &'a AppTypeRegistry,
codec: &'a CodecResource,
wasm_registry: &'a WasmComponentRegistry,
function_index: &'a FunctionIndex,
queries: &'a mut Queries<'a, 'a>,
query_resolver: &'a QueryResolver,
access: &'a ModAccess,
insert_despawn_component: &'a InsertDespawnComponent,
},
}
pub(crate) enum Config<'a, 'b, 'c, 'd, 'e, 'f, 'g> {
Setup(ConfigSetup<'a>),
RunSystem(ConfigRunSystem<'a, 'b, 'c, 'd, 'e, 'f, 'g>),
}
pub(crate) struct ConfigSetup<'a> {
pub(crate) world: &'a mut World,
pub(crate) add_systems: &'a mut AddSystems,
}
pub(crate) struct ConfigRunSystem<'a, 'b, 'c, 'd, 'e, 'f, 'g> {
pub(crate) commands: &'a mut Commands<'b, 'c>,
pub(crate) type_registry: &'a AppTypeRegistry,
pub(crate) codec: &'a CodecResource,
pub(crate) wasm_registry: &'a WasmComponentRegistry,
pub(crate) function_index: &'a FunctionIndex,
pub(crate) queries:
&'a mut ParamSet<'d, 'e, Vec<Query<'f, 'g, FilteredEntityMut<'static, 'static>>>>,
pub(crate) query_resolver: &'a QueryResolver,
pub(crate) access: ModAccess,
pub(crate) insert_despawn_component: InsertDespawnComponent,
}