Stream: wasmtime

Topic: Pass string to and return string back from WASM function


view this post on Zulip Tim Park (Mar 03 2022 at 23:30):

Is there an example or gist anywhere of how to pass a string parameter to and then return a string back from a WebAssembly function? The host and the WASM function are both written in Rust.

I'm trying this for the host:

        let func = instance
            .get_typed_func::<(i32, i32), i32, _>(&mut context.store, &request.function_name)?;

        unsafe {
            let message_ptr = request.message.as_ptr() as i32;
            let message_len = request.message.len() as i32;

            let ret_ptr = func.call(&mut context.store, (message_ptr, message_len))?;
            let ret_len = *((ret_ptr + 8) as *const i32) as usize;

            let state = String::from_utf8(Vec::from_raw_parts(
                *((ret_ptr + 0) as *const i32) as *mut _,
                ret_len,
                ret_len,
            ))?;

            ...
        }

and this as the WASM function:

#[no_mangle]
#[export_name = "handle_adjustment_message"]
unsafe extern "C" fn __wit_bindgen_handle_adjustment_message(
    arg0: i32,
    arg1: i32,
) -> i32 {
    let len0 = arg1 as usize;
    let message = String::from_utf8(Vec::from_raw_parts(arg0 as *mut _, len0, len0)).unwrap();

    ... process ..

    let ret_string: String = ...

    let vec3 = (ret_string.into_bytes()).into_boxed_slice();
    let ptr3 = vec3.as_ptr() as i32;
    let len3 = vec3.len() as i32;

    core::mem::forget(vec3);
    let ptr4 = RET_AREA.as_mut_ptr() as i32;
    *((ptr4 + 8) as *mut i32) = len3;
    *((ptr4 + 0) as *mut i32) = ptr3;
    ptr4
}

view this post on Zulip Dan Gohman (Mar 03 2022 at 23:35):

One way to do it is to write a wit file describing the API, and use wit-bindgen to generate the bindings. It supports string arguments and return values, and generates convenient Rust bindings for host and guest code.

view this post on Zulip Tim Park (Mar 03 2022 at 23:58):

Thanks @Dan Gohman - so if I have a .wit file that looks like:

handler: function(message: string) -> string

Then I should build the bindings for the host with:

$ wit-bindgen wasmtime --import handler.wit

and the rust WASM function with:

$ wit-bindgen rust-wasm --export handler.wit

Is that right?

If so, the WASM side bindings make sense and are straightforward, but the host side bindings include a reference to wit_bindgen_wasmtime which doesn't seem to exist as a crate?

view this post on Zulip Dan Gohman (Mar 03 2022 at 23:59):

wit_bindgen_wasmtime is in the wit-bindgen repo

view this post on Zulip Dan Gohman (Mar 04 2022 at 00:00):

It's not published on crates.io just yet.

view this post on Zulip Tim Park (Mar 04 2022 at 00:16):

Ah I see its in wit-bindgen/crates/wasmtime - ok, thanks.

Sorry - hopefully final question - is there any example that uses the generated host module/struct bindings? (In particular, confused on what to pass the get_state parameter of the new function.)

view this post on Zulip Dan Gohman (Mar 04 2022 at 00:25):

I don't know that offhand. I'll look into it and let you know

view this post on Zulip Tim Park (Mar 04 2022 at 16:00):

Thanks @Dan Gohman for all of your help - I think I have figured out most everything. The remaining issue I seem to be down to is figuring out why my WASM modules doesn't expose canonical_abi_free and canonical_abi_realloc.

Also for future readers @Radu Matei has an example repo here https://github.com/radu-matei/wasm-components-example

Contribute to radu-matei/wasm-components-example development by creating an account on GitHub.

view this post on Zulip Tim Park (Mar 04 2022 at 21:01):

... and answer to getting canonical_abi_free and canonical_abi_realloc exposed is to use the wit_bindgen_rust::export! macro ...


Last updated: Oct 23 2024 at 20:03 UTC