use crate::Wizer;
use crate::component::ComponentInstanceState;
use wasmtime::component::{
Component, ComponentExportIndex, Instance, Lift, WasmList, types::ComponentItem,
};
use wasmtime::{Result, Store, error::Context as _, format_err};
#[cfg(feature = "wasmprinter")]
use wasmtime::ToWasmtimeResult as _;
impl Wizer {
pub async fn run_component<T: Send>(
&self,
store: &mut Store<T>,
wasm: &[u8],
instantiate: impl AsyncFnOnce(&mut Store<T>, &Component) -> Result<Instance>,
) -> wasmtime::Result<Vec<u8>> {
let (cx, instrumented_wasm) = self.instrument_component(wasm)?;
#[cfg(feature = "wasmprinter")]
log::debug!(
"instrumented wasm: {}",
wasmprinter::print_bytes(&instrumented_wasm).to_wasmtime_result()?,
);
let engine = store.engine();
let component = Component::new(engine, &instrumented_wasm)
.context("failed to compile the Wasm component")?;
let index = self.validate_component_init_func(&component)?;
let instance = instantiate(store, &component).await?;
self.initialize_component(store, &instance, index).await?;
self.snapshot_component(cx, &mut WasmtimeWizerComponent { store, instance })
.await
}
fn validate_component_init_func(
&self,
component: &Component,
) -> wasmtime::Result<ComponentExportIndex> {
let init_func = self.get_init_func();
let (ty, index) = component
.get_export(None, init_func)
.ok_or_else(|| format_err!("the component does export the function `{init_func}`"))?;
let ty = match ty {
ComponentItem::ComponentFunc(ty) => ty,
_ => wasmtime::bail!("the component's `{init_func}` export is not a function",),
};
if ty.params().len() != 0 || ty.results().len() != 0 {
wasmtime::bail!(
"the component's `{init_func}` function export does not have type `[] -> []`",
);
}
Ok(index)
}
async fn initialize_component<T: Send>(
&self,
store: &mut Store<T>,
instance: &Instance,
index: ComponentExportIndex,
) -> wasmtime::Result<()> {
let init_func = instance
.get_typed_func::<(), ()>(&mut *store, index)
.expect("checked by `validate_init_func`");
init_func
.call_async(&mut *store, ())
.await
.with_context(|| format!("the initialization function trapped"))?;
Ok(())
}
}
pub struct WasmtimeWizerComponent<'a, T: 'static> {
pub store: &'a mut Store<T>,
pub instance: Instance,
}
impl<T: Send> WasmtimeWizerComponent<'_, T> {
async fn call_func<R, R2>(
&mut self,
instance: &str,
func: &str,
use_ret: impl FnOnce(&mut Store<T>, R) -> R2,
) -> R2
where
R: Lift + 'static,
{
log::debug!("invoking {instance}#{func}");
let (_, instance_export) = self
.instance
.get_export(&mut *self.store, None, instance)
.unwrap();
let (_, func_export) = self
.instance
.get_export(&mut *self.store, Some(&instance_export), func)
.unwrap();
let func = self
.instance
.get_typed_func::<(), (R,)>(&mut *self.store, func_export)
.unwrap();
let ret = func.call_async(&mut *self.store, ()).await.unwrap().0;
use_ret(&mut *self.store, ret)
}
}
impl<T: Send> ComponentInstanceState for WasmtimeWizerComponent<'_, T> {
async fn call_func_ret_list_u8(
&mut self,
instance: &str,
func: &str,
contents: impl FnOnce(&[u8]) + Send,
) {
self.call_func(instance, func, |store, list: WasmList<u8>| {
contents(list.as_le_slice(&store));
})
.await
}
async fn call_func_ret_s32(&mut self, instance: &str, func: &str) -> i32 {
self.call_func(instance, func, |_, r| r).await
}
async fn call_func_ret_s64(&mut self, instance: &str, func: &str) -> i64 {
self.call_func(instance, func, |_, r| r).await
}
async fn call_func_ret_f32(&mut self, instance: &str, func: &str) -> u32 {
self.call_func(instance, func, |_, r: f32| r.to_bits())
.await
}
async fn call_func_ret_f64(&mut self, instance: &str, func: &str) -> u64 {
self.call_func(instance, func, |_, r: f64| r.to_bits())
.await
}
}