-
I have a pybadge and I'm trying to run on it wasmi combined with pybadge_high and embedded_graphics. I want to define a host function that the wasm code can call to print an i32 number on the screen. The problem is that the display where I want to write the number must be mutable to be able to write into it. And so using it inside an anonymous function turns it from Is there a way to mutate a state from a host-provided function? Here is the code I have so far: #![no_std]
#![no_main]
use embedded_graphics::{
mono_font::{ascii::FONT_6X10, MonoTextStyle},
pixelcolor::Rgb565,
prelude::*,
text::Text,
};
use pybadge::{prelude::*, *};
use pybadge_high as pybadge;
use wasmi::*;
type HostState = u32;
#[entry]
fn main() -> ! {
let mut pybadge = PyBadge::take().unwrap();
pybadge.display.clear(Color::RED).unwrap();
let style = MonoTextStyle::new(&FONT_6X10, Rgb565::WHITE);
let engine = Engine::default();
let bytes = include_bytes!("../demo.wasm");
let module = Module::new(&engine, &bytes[..]).unwrap();
let mut store = Store::new(&engine, 42);
# this doesn't work:
let echo_i32 = Func::wrap(&mut store, |caller: Caller<'_, HostState>, param: i32| {
Text::new("v: {param}", Point::new(20, 30), style)
.draw(&mut pybadge.display)
.unwrap();
});
let mut linker = <Linker<HostState>>::new(&engine);
linker.define("pybadge", "echo_i32", echo_i32).unwrap();
let instance = linker
.instantiate(&mut store, &module)
.unwrap()
.start(&mut store)
.unwrap();
let update = instance.get_typed_func::<(), ()>(&store, "update").unwrap();
update.call(&mut store, ()).unwrap();
loop {}
} And the error:
|
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Use cases like these are the reason why the So you need to define your own host state type that includes whatever you want to mutate in host functions: pub struct HostState {
pub pybadge: PyBadge,
} and #[entry]
fn main() -> ! {
let mut pybadge = PyBadge::take().unwrap();
pybadge.display.clear(Color::RED).unwrap();
let style = MonoTextStyle::new(&FONT_6X10, Rgb565::WHITE);
let engine = Engine::default();
let bytes = include_bytes!("../demo.wasm");
let module = Module::new(&engine, &bytes[..]).unwrap();
let mut store = <Store<HostState>>::new(&engine, pybadge);
let echo_i32 = Func::wrap(&mut store, |caller: Caller<'_, HostState>, param: i32| {
Text::new("v: {param}", Point::new(20, 30), style)
.draw(&mut caller.data_mut().pybadge.display)
.unwrap();
});
// ...
} |
Beta Was this translation helpful? Give feedback.
Use cases like these are the reason why the
Store
is generic over a so-calledHostState
type and while host functions as created withFunc::wrap
are notFnMut
and thus cannot change their own state, they can change the host state if they accept a first parameter asCaller
which works very similar to Wasmtime's API: https://docs.rs/wasmtime/17.0.1/wasmtime/struct.Func.html#method.wrapSo you need to define your own host state type that includes whatever you want to mutate in host functions:
and