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 { /// Same as [`Wizer::run`], except for components. pub async fn run_component( &self, store: &mut Store, wasm: &[u8], instantiate: impl AsyncFnOnce(&mut Store, &Component) -> Result, ) -> wasmtime::Result> { 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 { 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( &self, store: &mut Store, 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(()) } } /// Impementation of [`ComponentInstanceState`] backed by Wasmtime. pub struct WasmtimeWizerComponent<'a, T: 'static> { /// The Wasmtime-based store that owns the `instance` field. pub store: &'a mut Store, /// The instance that this will load state from. pub instance: Instance, } impl WasmtimeWizerComponent<'_, T> { async fn call_func( &mut self, instance: &str, func: &str, use_ret: impl FnOnce(&mut Store, 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 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| { 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 } }