wasmtime_wizer/component/
wasmtime.rs1use crate::Wizer;
2use crate::component::ComponentInstanceState;
3use wasmtime::component::{
4 Component, ComponentExportIndex, Instance, Lift, Val, WasmList, types::ComponentItem,
5};
6use wasmtime::{Result, Store, error::Context as _, format_err};
7
8#[cfg(feature = "wasmprinter")]
9use wasmtime::ToWasmtimeResult as _;
10
11impl Wizer {
12 pub async fn run_component<T: Send>(
14 &self,
15 store: &mut Store<T>,
16 wasm: &[u8],
17 instantiate: impl AsyncFnOnce(&mut Store<T>, &Component) -> Result<Instance>,
18 ) -> wasmtime::Result<(Vec<u8>, Vec<Val>)> {
19 let (cx, instrumented_wasm) = self.instrument_component(wasm)?;
20
21 #[cfg(feature = "wasmprinter")]
22 log::debug!(
23 "instrumented wasm: {}",
24 wasmprinter::print_bytes(&instrumented_wasm).to_wasmtime_result()?,
25 );
26
27 let engine = store.engine();
28 let component = Component::new(engine, &instrumented_wasm)
29 .context("failed to compile the Wasm component")?;
30 let (index, args, mut rets) = self.validate_component_init_func(&component)?;
31
32 let instance = instantiate(store, &component).await?;
33 self.initialize_component(store, &instance, index, args, &mut rets)
34 .await?;
35 let snap = self
36 .snapshot_component(&cx, &mut WasmtimeWizerComponent { store, instance })
37 .await?;
38 Ok((snap, rets))
39 }
40
41 fn validate_component_init_func(
42 &self,
43 component: &Component,
44 ) -> wasmtime::Result<(ComponentExportIndex, Vec<Val>, Vec<Val>)> {
45 let init_func = self.get_init_func();
46
47 use wasmtime::component::wasm_wave::{untyped::UntypedFuncCall, wasm::WasmFunc};
48 use wasmtime::component::wit_parser::ItemName;
49 let (func_name, func_call) = if init_func.contains('(') {
50 let call = UntypedFuncCall::parse(init_func)
51 .with_context(|| format!("parsing `{init_func}` as wave function call"))?;
52 let item_name = call
53 .item_name()
54 .map_err(wasmtime::Error::from_anyhow)
55 .with_context(|| format!("parsing `{init_func}` as wave function call"))?;
56 (item_name, Some(call))
57 } else {
58 (
59 init_func
60 .parse::<ItemName>()
61 .map_err(wasmtime::Error::from_anyhow)
62 .with_context(|| format!("parsing `{init_func}` as wit item name"))?,
63 None,
64 )
65 };
66
67 let (ty, index) = component
68 .get_export(None, func_name)
69 .ok_or_else(|| format_err!("the component does export the function `{init_func}`"))?;
70
71 let ty = match ty {
72 ComponentItem::ComponentFunc(ty) => ty,
73 _ => wasmtime::bail!("the component's `{init_func}` export is not a function",),
74 };
75
76 if let Some(func_call) = func_call {
77 let param_types = WasmFunc::params(&ty).collect::<Vec<_>>();
78 let param_vals = func_call.to_wasm_params(¶m_types).with_context(|| {
79 format!("parsing `{init_func}` params as types {param_types:?}")
80 })?;
81 Ok((
82 index,
83 param_vals,
84 vec![Val::Bool(false); ty.results().len()],
85 ))
86 } else {
87 if ty.params().len() != 0 || ty.results().len() != 0 {
88 wasmtime::bail!(
89 "the component's `{init_func}` function export does not have type `[] -> []`",
90 );
91 }
92 Ok((index, vec![], vec![]))
93 }
94 }
95
96 async fn initialize_component<T: Send>(
97 &self,
98 store: &mut Store<T>,
99 instance: &Instance,
100 index: ComponentExportIndex,
101 args: Vec<Val>,
102 rets: &mut Vec<Val>,
103 ) -> wasmtime::Result<()> {
104 let init_func = instance
105 .get_func(&mut *store, index)
106 .expect("checked by `validate_init_func`");
107 init_func
108 .call_async(&mut *store, &args, rets)
109 .await
110 .with_context(|| format!("the initialization function trapped"))?;
111 Ok(())
112 }
113}
114
115pub struct WasmtimeWizerComponent<'a, T: 'static> {
117 pub store: &'a mut Store<T>,
119 pub instance: Instance,
121}
122
123impl<T: Send> WasmtimeWizerComponent<'_, T> {
124 async fn call_func<R, R2>(
125 &mut self,
126 instance: &str,
127 func: &str,
128 use_ret: impl FnOnce(&mut Store<T>, R) -> R2,
129 ) -> R2
130 where
131 R: Lift + 'static,
132 {
133 log::debug!("invoking {instance}#{func}");
134 let (_, instance_export) = self
135 .instance
136 .get_export(&mut *self.store, None, instance)
137 .unwrap();
138 let (_, func_export) = self
139 .instance
140 .get_export(&mut *self.store, Some(&instance_export), func)
141 .unwrap();
142 let func = self
143 .instance
144 .get_typed_func::<(), (R,)>(&mut *self.store, func_export)
145 .unwrap();
146 let ret = func.call_async(&mut *self.store, ()).await.unwrap().0;
147 use_ret(&mut *self.store, ret)
148 }
149}
150
151impl<T: Send> ComponentInstanceState for WasmtimeWizerComponent<'_, T> {
152 async fn call_func_ret_list_u8(
153 &mut self,
154 instance: &str,
155 func: &str,
156 contents: impl FnOnce(&[u8]) + Send,
157 ) {
158 self.call_func(instance, func, |store, list: WasmList<u8>| {
159 contents(list.as_le_slice(&store));
160 })
161 .await
162 }
163
164 async fn call_func_ret_s32(&mut self, instance: &str, func: &str) -> i32 {
165 self.call_func(instance, func, |_, r| r).await
166 }
167
168 async fn call_func_ret_s64(&mut self, instance: &str, func: &str) -> i64 {
169 self.call_func(instance, func, |_, r| r).await
170 }
171
172 async fn call_func_ret_f32(&mut self, instance: &str, func: &str) -> u32 {
173 self.call_func(instance, func, |_, r: f32| r.to_bits())
174 .await
175 }
176
177 async fn call_func_ret_f64(&mut self, instance: &str, func: &str) -> u64 {
178 self.call_func(instance, func, |_, r: f64| r.to_bits())
179 .await
180 }
181}