Hi,
i'm having difficulty troubleshooting the following case:
i have a simple WIT definition shared between a basic guest and a basic host.
WIT:
default world demo {
record polarity-scores {
positive: float64,
negative: float64,
neutral: float64,
compound: float64
}
export sentiment: func(input:list<string>) -> list<polarity-scores>
}
the guest code compiles successfully:
wit_bindgen::generate!({
world: "demo",
path: "./wit",
});
struct DemoImpl;
impl Demo for DemoImpl {
fn sentiment(input: Vec<String>) -> Vec<Polarityscores> {
lazy_static::lazy_static! {
static ref ANALYZER: vader_sentiment::SentimentIntensityAnalyzer<'static> =
vader_sentiment::SentimentIntensityAnalyzer::new();
}
input
.iter()
.map(|s| {
let scores = ANALYZER.polarity_scores(s.as_str());
Polarityscores {
positive: scores["pos"],
negative: scores["neg"],
neutral: scores["neu"],
compound: scores["compound"],
}
})
.collect()
}
}
export_demo!(DemoImpl);
and the host code compiles successfully:
use anyhow::Result;
use host::{add_to_linker, WasiCtx};
use stopwatch::Stopwatch;
use wasi_cap_std_sync::WasiCtxBuilder;
use wasmtime::{
component::{Component, Linker},
Config, Engine, Store, WasmBacktraceDetails,
};
wasmtime::component::bindgen!({
world: "demo",
path: "../guest/wit",
async: true,
});
#[tokio::main]
async fn main() -> Result<()> {
println!("starting");
let wasm = "<...>/guest.wasm";
let mut config = Config::new();
config.cache_config_load_default().unwrap();
config.wasm_backtrace_details(WasmBacktraceDetails::Enable);
config.wasm_component_model(true);
config.async_support(true);
let engine = Engine::new(&config).unwrap();
let mut linker = Linker::new(&engine);
add_to_linker(&mut linker, |x| x).unwrap();
let stopwatch = Stopwatch::start_new();
println!("calling Component::from_file()");
let component = Component::from_file(&engine, wasm).unwrap(); // <--- this fails :-(
println!(
"completed Component::from_file() in {} millis",
stopwatch.elapsed().as_millis()
);
let comments = vec![
"I love rust!",
"ham is not a good sandwich",
"do you think we should go to the store today?",
"meetings are the favorite part of my day",
"bob is your uncle",
"I really hate the beach on a rainy day...",
"hello bob! you are looking great today!",
];
let occurrences = 1;
let mut input1 = Vec::with_capacity(occurrences * comments.len());
for _i in 0..occurrences {
for comment in comments.iter() {
input1.push(comment.to_string());
}
}
let iterations = 1;
for _i in 0..iterations {
let stopwatch = Stopwatch::start_new();
let mut store = Store::new(
&engine,
WasiCtxBuilder::new()
.inherit_stdin()
.inherit_stdout()
.build(),
);
let (_demo, instance) = Demo::instantiate_async(&mut store, &component, &linker)
.await
.unwrap();
let func = instance
.get_typed_func::<(&[String],), (Vec<PolarityScores>,), &mut Store<WasiCtx>>(
&mut store,
"sentiment",
)?;
let (results,) = func.call_async(&mut store, (input1.as_slice(),)).await?;
println!(
"sentiment(): processed {} values in {} millis",
input1.len(),
stopwatch.elapsed().as_millis(),
);
for (i, r) in results.iter().enumerate() {
println!("input: '{}', output: '{:?}'", input1[i], r);
}
}
Ok(())
}
[package]
name = "host"
version = "0.1.0"
edition = "2021"
[dependencies]
stopwatch = "0.0.7"
anyhow = "1.0.69"
tokio = { version = "1.25", features = ["full"] }
wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", features = ["component-model"], branch = 'release-6.0.0' }
host = { git = "https://github.com/bytecodealliance/preview2-prototyping" }
wasi-cap-std-sync = { git = "https://github.com/bytecodealliance/preview2-prototyping" }
however when running the host it fails to load the component with the following error:
thread 'main' panicked at 'index out of bounds: the len is 9 but the index is 9', <...>\.cargo\git\checkouts\wasmtime-41807828cb3a7a7e\f3dfad2\crates\environ\src\component\types.rs:425:9
if i change the exported function (including guest implementation) to return a simple type (e.g. float64
instead of the record polarity-scores
) everything works as expected.
any ideas why my record definition is causing issues?
I think this is a case of incomplete and buggy, the prototyping repo is really only intended for people who want to dig in the code and implement all the missing parts, it's not ready for end use
I think you're running into a bug fixed in https://github.com/bytecodealliance/wasmtime/pull/5777, can you try the main
branch of Wasmtime?
This is actually not possible to get wasmtime from main, and pulling host on the prototype :(
yep, it'll require editing code as opposed to using everything as-is
for my current needs, i can workaround this by using basic types instead of a record
.
looking forward to leveraging the fix you mentioned in the future
(BTW - is there any estimated timeline or plan you can link to, for getting the officially released wit-bindgen
& wasmtime
crates in crates.io, with this scenario being functional?)
Alex Crichton said:
yep, it'll require editing code as opposed to using everything as-is
Are you talking about forking yhe repo? Because for now, to make a WASI Component work, there is no other way than to import the host from preview prototyping?
you can depend on a local checkout and edit around in there, you only need a fork at the point where you might want to make a PR with your changes
Last updated: Dec 23 2024 at 13:07 UTC