Description
Add host functions for components.
Wasmtime has 2 APIs for adding host functions to components:
- The typed API (e.g.
func_wrap
) which requires the signature be known at compile time. - The dynamic API (e.g.
func_new
), where the params are in a&[Val]
and return values are to be written to a&mut[Val]
.
I think (1) essentially requires a rust compiler thus out of question. We're left with (2). But how do we wrap such API in Ruby?
Option A: follow the crate's API
Params are Ruby values converted from Wasm, return values are tagged with their type:
# Imagine the following WIT definitions:
# f(param1: string) -> result<a>
#
# record a {
# field1: u32,
# field2: string,
# }
T = Wasmtime::Component::Type # Hypothetical API, does not exist yet
linker_istance.func_new("f") do |_store, param1|
T::Result.wrap(
Wasmtime::Component::Result.ok(
T::Record.wrap(
field1: T::U32.wrap(42),
field2: T::String.wrap("foo"),
)
)
)
end
With this approach, params are not type-checked. E.g. param1
could be of any type; whatever the caller decides to send. The host function could implement some limited type checking (limited because it can't distinguish between a u8 or u32, for example).
Option B: type the function
Similar to what's done for core Wasm functions, specify the return type when calling #func_new
:
T = Wasmtime::Component::Type # Hypothetical API, does not exist yet
A = T::Record.new(
"field1" => T::U32
"field1" => T::String
)
ReturnType = T::Result.new(A)
linker_istance.func_new("f", ReturnType) do |_store, param1|
record = { "field1" => 42, "field2" => "foo" }
Wasmtime::Component::Result.ok(record)
end
This approach can be extended to support params type checking (possibly with a performance hit).
We might be able to generate those types directly by parsing a WIT file.
Both options A and B require mapping a Ruby object to a Wasm component type definition in a standalone way. By standalone I mean not using an index to point into a type in a component, i.e. not using the wasmtime::component::Type
enum. The implication of this is the convert code needs to be duplicated or a new abstraction introduced.
There may be a better way. If you think of one, please share! Unless we find a better way, I suggest waiting until users really need this feature before implementing this.