from_witx!() { /* proc-macro */ }
Expand description
This macro expands to a set of pub
Rust modules:
-
The
types
module contains definitions for eachtypename
declared in the witx document. Type names are translated to the Rust-idiomatic CamelCase. -
For each
module
defined in the witx document, a Rust module is defined containing definitions for that module. Module names are translated to the Rust-idiomatic snake_case.-
For each
@interface func
defined in a witx module, an abi-level function is generated which takes ABI-level arguments, along with a ref that impls the module trait, and aGuestMemory
implementation. Users typically won’t use these abi-level functions: Either thewasmtime_integration
macro or thelucet-wiggle
crates adapt these to work with a particular WebAssembly engine. -
A public “module trait” is defined (called the module name, in SnakeCase) which has a
&self
method for each function in the module. These methods takes idiomatic Rust types for each argument and returnResult<($return_types),$error_type>
-
When the
wiggle
crate is built with thewasmtime_integration
feature, each module contains anadd_to_linker
function to add it to awasmtime::Linker
.
-
Arguments are provided using Rust struct value syntax.
witx
takes a list of string literal paths. Paths are relative to the CARGO_MANIFEST_DIR of the crate where the macro is invoked. Alternatively,witx_literal
takes a string containing a complete witx document.- Optional:
errors
takes a mapping of witx identifiers to types, e.g{ errno => YourErrnoType }
. This allows you to use theUserErrorConversion
trait to map these rich errors into the flat witx type, or to terminate WebAssembly execution by trapping.- Instead of requiring the user to define an error type, wiggle can
generate an error type for the user which has conversions to/from
the base type, and permits trapping, using the syntax
errno => trappable AnErrorType
.
- Instead of requiring the user to define an error type, wiggle can
generate an error type for the user which has conversions to/from
the base type, and permits trapping, using the syntax
- Optional:
async
takes a set of witx modules and functions which are made Rustasync
functions in the module trait.
§Example
use wiggle::GuestPtr;
wiggle::from_witx!({
witx_literal: "
(typename $errno
(enum (@witx tag u32)
$ok
$invalid_arg
$io
$overflow))
(typename $alias_to_float f32)
(module $example
(@interface func (export \"int_float_args\")
(param $an_int u32)
(param $some_floats (list f32))
(result $r (expected (error $errno))))
(@interface func (export \"double_int_return_float\")
(param $an_int u32)
(result $r (expected $alias_to_float (error $errno)))))
",
errors: { errno => YourRichError },
async: { example::double_int_return_float },
});
/// Witx generates a set of traits, which the user must impl on a
/// type they define. We call this the ctx type. It stores any context
/// these functions need to execute.
pub struct YourCtxType {}
/// Witx provides a hook to translate "rich" (arbitrary Rust type) errors
/// into the flat error enums used at the WebAssembly interface. You will
/// need to impl the `types::UserErrorConversion` trait to provide a translation
/// from this rich type.
#[derive(Debug)]
pub enum YourRichError {
InvalidArg(String),
Io(std::io::Error),
Overflow,
Trap(String),
}
/// The above witx text contains one module called `$example`. So, we must
/// implement this one method trait for our ctx type.
#[wiggle::async_trait]
/// We specified in the `async_` field that `example::double_int_return_float`
/// is an asynchronous method. Therefore, we use the `async_trait` proc macro
/// to define this trait, so that `double_int_return_float` can be an `async fn`.
/// `wiggle::async_trait` is defined as `#[async_trait::async_trait(?Send)]` -
/// in wiggle, async methods do not have the Send constraint.
impl example::Example for YourCtxType {
/// The arrays module has two methods, shown here.
/// Note that the `GuestPtr` type comes from `wiggle`,
/// whereas the witx-defined types like `Excuse` and `Errno` come
/// from the `pub mod types` emitted by the `wiggle::from_witx!`
/// invocation above.
fn int_float_args(&mut self, _int: u32, _floats: &GuestPtr<[f32]>)
-> Result<(), YourRichError> {
unimplemented!()
}
async fn double_int_return_float(&mut self, int: u32)
-> Result<f32, YourRichError> {
Ok(int.checked_mul(2).ok_or(YourRichError::Overflow)? as f32)
}
}
/// For all types used in the `error` an `expected` in the witx document,
/// you must implement `GuestErrorType` which tells wiggle-generated
/// code what value to return when the method returns Ok(...).
impl wiggle::GuestErrorType for types::Errno {
fn success() -> Self {
unimplemented!()
}
}
/// If you specify a `error` mapping to the macro, you must implement the
/// `types::UserErrorConversion` for your ctx type as well. This trait gives
/// you an opportunity to store or log your rich error type, while returning
/// a basic witx enum to the WebAssembly caller. It also gives you the ability
/// to terminate WebAssembly execution by trapping.
impl types::UserErrorConversion for YourCtxType {
fn errno_from_your_rich_error(&mut self, e: YourRichError)
-> Result<types::Errno, wiggle::wasmtime_crate::Error>
{
println!("Rich error: {:?}", e);
match e {
YourRichError::InvalidArg{..} => Ok(types::Errno::InvalidArg),
YourRichError::Io{..} => Ok(types::Errno::Io),
YourRichError::Overflow => Ok(types::Errno::Overflow),
YourRichError::Trap(s) => Err(wiggle::wasmtime_crate::Error::msg(s)),
}
}
}