component_init_wasmtime/
lib.rs

1use anyhow::{Context, Result, anyhow};
2use component_init_transform::Invoker;
3use wasmtime::{
4    Config, Engine, Store,
5    component::{Component, ComponentNamedList, Instance, Lift, Linker},
6};
7
8pub async fn initialize(component: &[u8]) -> Result<Vec<u8>> {
9    component_init_transform::initialize(component, |instrumented| {
10        Box::pin(async move {
11            let i = invoker(instrumented)
12                .await
13                .context("running instrumented component")?;
14            let i: Box<dyn Invoker> = Box::new(i);
15            Ok(i)
16        })
17    })
18    .await
19}
20
21async fn invoker(component: Vec<u8>) -> Result<Impl> {
22    let mut config = Config::new();
23    config.async_support(true);
24    let engine = Engine::new(&config).context("creating engine")?;
25    let component =
26        Component::new(&engine, &component).context("compiling instrumented component")?;
27    let mut linker = Linker::new(&engine);
28    linker
29        .define_unknown_imports_as_traps(&component)
30        .context("link unknown imports as traps")?;
31    let mut store = Store::new(&engine, Ctx);
32    let instance = linker
33        .instantiate_async(&mut store, &component)
34        .await
35        .context("instantiate")?;
36    let mut this = Impl { instance, store };
37    this.call::<()>("component-init")
38        .await
39        .context("running the component-init export func")?;
40    Ok(this)
41}
42
43pub struct Ctx;
44
45struct Impl {
46    instance: Instance,
47    store: Store<Ctx>,
48}
49
50impl Impl {
51    async fn call<T: ComponentNamedList + Lift + Send + Sync>(&mut self, name: &str) -> Result<T> {
52        let export = self
53            .instance
54            .get_export_index(&mut self.store, None, name)
55            .ok_or_else(|| anyhow!("{name} is not exported"))?;
56        let func = self
57            .instance
58            .get_func(&mut self.store, export)
59            .ok_or_else(|| anyhow!("{name} export is not a func"))?;
60        let func = func
61            .typed::<(), T>(&mut self.store)
62            .with_context(|| format!("type of {name} func"))?;
63        let r = func
64            .call_async(&mut self.store, ())
65            .await
66            .with_context(|| format!("executing {name}"))?;
67        func.post_return_async(&mut self.store)
68            .await
69            .with_context(|| format!("post-return {name}"))?;
70        Ok(r)
71    }
72}
73
74#[async_trait::async_trait]
75impl Invoker for Impl {
76    async fn call_s32(&mut self, name: &str) -> Result<i32> {
77        Ok(self.call::<(i32,)>(name).await?.0)
78    }
79    async fn call_s64(&mut self, name: &str) -> Result<i64> {
80        Ok(self.call::<(i64,)>(name).await?.0)
81    }
82    async fn call_f32(&mut self, name: &str) -> Result<f32> {
83        Ok(self.call::<(f32,)>(name).await?.0)
84    }
85    async fn call_f64(&mut self, name: &str) -> Result<f64> {
86        Ok(self.call::<(f64,)>(name).await?.0)
87    }
88    async fn call_list_u8(&mut self, name: &str) -> Result<Vec<u8>> {
89        Ok(self.call::<(Vec<u8>,)>(name).await?.0)
90    }
91}