Stream: general

Topic: Understanding host-defined callbacks


view this post on Zulip Ben Little (Jun 12 2023 at 16:53):

I'm trying to build a runtime that passes callbacks to WASM modules. For example the host may open a connection to a remote API but does not want to pass full control of that API to a module and instead passes a callback that in some way validates the request before sending it.

I'm using wasmtime from Rust and the only example I can find uses Func::wrap to define a function that can be placed in the store for the module to access. However I'm not sure if this is really a callback in that I'm not sure if it actually passes control back to the host

I really want something like a trap that says "okay, I've put the relevant data in the store, now I want to host to do something". Is this something that wasmtime supports? Or do I need to rethink the control flow by executing a module function to completion, pausing to do host stuff, then executing the next function?

view this post on Zulip Lann Martin (Jun 12 2023 at 16:56):

There is no separate "callback" functionality per-se; a function defined via Func::wrap does indeed call back into the host.

view this post on Zulip Ben Little (Jun 12 2023 at 17:12):

Thanks! I guess my next question is how IntoFunc works because right now the compiler error doesn't give a lot of info. I tried creating a callback like this:

let api_get = Func::wrap(
    &mut store,
    |mut caller: Caller<'_, State>, id: u32| {
        if validate(id) {
            match api.get(id) {
                Ok(data) => return Some(data),
                _ => {}
            };
        }
        return None
    },
);

But this doesn't satisfy IntoFunc for reasons unknown to me. How do I express that this function should accept parameters and return a value?

view this post on Zulip Lann Martin (Jun 12 2023 at 17:22):

I believe the issue is that you're returning Option<_>. You'll have to find a way to represent the return value as one (or more, if your guests support multi-value) primitive wasm types.

view this post on Zulip Ben Little (Jun 12 2023 at 17:28):

I've been playing with it a bit and I agree that is one of the issues. However what's confusing me is the closure signature. The compiler is not happy with |caller, id| or |id, caller| or |caller| |id|.

view this post on Zulip Ben Little (Jun 12 2023 at 17:30):

Like this doesn't satisfy IntoFunc:

Func::wrap::<State, u32, u32>(&mut store, |mut caller: Caller<'_, State>, id: u32| {
     return 5
});

view this post on Zulip Lann Martin (Jun 12 2023 at 17:32):

For that one I believe it would be <State, (u32,), u32>

view this post on Zulip Ben Little (Jun 12 2023 at 17:36):

Ok this works:

Func::wrap::<State, (u32,), u32>(&mut store, |id: u32| {
    return 5
});

but then I lose the Caller context. For my purposes I may not need it, though.

view this post on Zulip Ben Little (Jun 12 2023 at 17:36):

Thanks again for your help Lann!


Last updated: Oct 23 2024 at 20:03 UTC