Working with externref
You can also browse this source code online and clone the wasmtime repository to run the example locally.
This example shows how to pass opaque host references into and out of WebAssembly using externref
.
externref.wat
(module
(table $table (export "table") 10 externref)
(global $global (export "global") (mut externref) (ref.null extern))
(func (export "func") (param externref) (result externref)
local.get 0
)
)
externref.rs
//! Small example of how to use `externref`s.
// You can execute this example with `cargo run --example externref`
use wasmtime::*;
fn main() -> Result<()> {
println!("Initializing...");
let mut config = Config::new();
config.wasm_reference_types(true);
let engine = Engine::new(&config)?;
let mut store = Store::new(&engine, ());
println!("Compiling module...");
let module = Module::from_file(&engine, "examples/externref.wat")?;
println!("Instantiating module...");
let instance = Instance::new(&mut store, &module, &[])?;
println!("Creating new `externref`...");
let externref = match ExternRef::new(&mut store, "Hello, World!") {
Ok(x) => x,
Err(e) => match e.downcast::<GcHeapOutOfMemory<&str>>() {
Ok(oom) => {
let (inner, oom) = oom.take_inner();
store.gc(Some(&oom));
ExternRef::new(&mut store, inner)?
}
Err(e) => return Err(e),
},
};
assert!(
externref
.data(&store)?
.expect("should have host data")
.is::<&'static str>()
);
assert_eq!(
*externref
.data(&store)?
.expect("should have host data")
.downcast_ref::<&'static str>()
.unwrap(),
"Hello, World!"
);
println!("Touching `externref` table...");
let table = instance.get_table(&mut store, "table").unwrap();
table.set(&mut store, 3, Some(externref).into())?;
let elem = table
.get(&mut store, 3)
.unwrap() // assert in bounds
.unwrap_extern() // assert it's an externref table
.copied()
.unwrap(); // assert the externref isn't null
assert!(Rooted::ref_eq(&store, &elem, &externref)?);
println!("Touching `externref` global...");
let global = instance.get_global(&mut store, "global").unwrap();
global.set(&mut store, Some(externref).into())?;
let global_val = global.get(&mut store).unwrap_externref().copied().unwrap();
assert!(Rooted::ref_eq(&store, &global_val, &externref)?);
println!("Calling `externref` func...");
let func = instance.get_typed_func::<Option<Rooted<ExternRef>>, Option<Rooted<ExternRef>>>(
&mut store, "func",
)?;
let ret = func.call(&mut store, Some(externref))?;
assert!(ret.is_some());
assert!(Rooted::ref_eq(&store, &ret.unwrap(), &externref)?);
println!("GCing within the store...");
store.gc(None);
println!("Done.");
Ok(())
}