wasm_embedded_rt_wasmtime/
lib.rs

1/// Wasmtime runtime support
2
3
4pub use wasm_embedded_spec::{self as spec};
5
6use spec::Error;
7use spec::api::{UserErrorConversion, types::Errno};
8
9use wasmtime::*;
10use wasmtime_wasi::{WasiCtx, WasiCtxBuilder};
11
12
13mod gpio;
14mod spi;
15mod i2c;
16mod uart;
17
18/// Wasmtime runtime object
19pub struct WasmtimeRuntime<E> {
20    _engine: wasmtime::Engine,
21    linker: Linker<Context<E>>,
22    store: Store<Context<E>>,
23}
24
25struct Context<E> {
26    wasi: WasiCtx,
27    engine: E,
28}
29
30pub trait Engine: spec::gpio::Gpio + spec::i2c::I2c + spec::spi::Spi + spec::uart::Uart {}
31
32impl <T> Engine for T where
33    T: spec::gpio::Gpio + spec::i2c::I2c + spec::spi::Spi + spec::uart::Uart,
34{
35}
36
37impl <E: Engine> Context<E> {
38    pub fn new(engine: E) -> Self {
39
40        let wasi = WasiCtxBuilder::new()
41            .inherit_stdio()
42            .inherit_args().unwrap()
43            .build();
44
45        Context {
46            wasi,
47            engine
48        }
49    }
50}
51
52impl <E: Engine> UserErrorConversion for Context<E> {
53    fn errno_from_error(&mut self, e: spec::Error) -> Result<spec::api::types::Errno, anyhow::Error> {
54        match e {
55            Error::InvalidArg => Ok(Errno::InvalidArg),
56            Error::Unexpected => Ok(Errno::Unexpected),
57            Error::Failed => Ok(Errno::Failed),
58            Error::NoDevice => Ok(Errno::NoDevice),
59            Error::Unsupported => Ok(Errno::Unsupported),
60        }
61    }
62}
63
64impl <E: Engine + 'static> WasmtimeRuntime<E> {
65    /// Create a new WasmtimeRuntime with the provided engine and application
66    pub fn new(engine: E, bin: &[u8]) -> anyhow::Result<Self> {
67        // Create new linker with the provided engine
68        let wasm_engine = wasmtime::Engine::default();
69        let mut linker = Linker::new(&wasm_engine);
70
71        // Setup store and context
72        let context = Context::new(engine);
73        let mut store = Store::new(&wasm_engine, context);
74
75        // Bind WASI
76        wasmtime_wasi::add_to_linker(&mut linker, |ctx: &mut Context<E>| &mut ctx.wasi )?;
77
78        // Bind drivers
79        spec::api::gpio::add_to_linker(&mut linker, move |c: &mut Context<E>| c)?;
80        spec::api::spi::add_to_linker(&mut linker, move |c: &mut Context<E>| c)?;
81        spec::api::i2c::add_to_linker(&mut linker, move |c: &mut Context<E>| c)?;
82        spec::api::uart::add_to_linker(&mut linker, move |c: &mut Context<E>| c)?;
83
84        // Load module from file
85        let module = Module::from_binary(&wasm_engine, bin)?;
86        linker.module(&mut store, "", &module)?;
87
88        Ok(Self{ _engine: wasm_engine, linker, store })
89    }
90
91    /// Run the loaded application
92    pub fn run(&mut self) -> anyhow::Result<()> {
93        let Self{linker, ..} = self;
94
95        linker
96            .get_default(&mut self.store, "")?
97            .typed::<(), (), _>(&self.store)?
98            .call(&mut self.store, ())?;
99
100        Ok(())
101    }
102}