Files
wasmtime/tests/all/component_model/macros.rs
Joel Dice 22fb3ecbbf add ComponentType/Lift/Lower derive macro for record types (#4337)
This is the first stage of implementing
https://github.com/bytecodealliance/wasmtime/issues/4308, i.e. derive macros for
`ComponentType`, `Lift`, and `Lower` for composite types in the component model.
This stage only covers records; I expect the other composite types will follow a
similar pattern.

It borrows heavily from the work Jamey Sharp did in
https://github.com/bytecodealliance/wasmtime/pull/4217.  Thanks for that, and
thanks to both Jamey and Alex Crichton for their excellent review feedback.
Thanks also to Brian for pairing up on the initial draft.

Signed-off-by: Joel Dice <joel.dice@fermyon.com>
2022-06-29 09:38:36 -05:00

159 lines
4.4 KiB
Rust

use super::TypedFuncExt;
use anyhow::Result;
use std::fmt::Write;
use wasmtime::component::{Component, ComponentType, Lift, Linker, Lower};
use wasmtime::Store;
fn make_echo_component(type_definition: &str, type_size: u32) -> String {
if type_size <= 4 {
format!(
r#"
(component
(core module $m
(func (export "echo") (param i32) (result i32)
local.get 0
)
(memory (export "memory") 1)
)
(core instance $i (instantiate $m))
{}
(func (export "echo") (param $Foo) (result $Foo)
(canon lift (core func $i "echo") (memory $i "memory"))
)
)"#,
type_definition
)
} else {
let mut params = String::new();
let mut store = String::new();
for index in 0..(type_size / 4) {
params.push_str(" i32");
write!(
&mut store,
"(i32.store offset={} (local.get $base) (local.get {}))",
index * 4,
index,
)
.unwrap();
}
format!(
r#"
(component
(core module $m
(func (export "echo") (param{}) (result i32)
(local $base i32)
(local.set $base (i32.const 0))
{}
local.get $base
)
(memory (export "memory") 1)
)
(core instance $i (instantiate $m))
{}
(func (export "echo") (param $Foo) (result $Foo)
(canon lift (core func $i "echo") (memory $i "memory"))
)
)"#,
params, store, type_definition
)
}
}
#[test]
fn record_derive() -> Result<()> {
#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
#[component(record)]
struct Foo {
#[component(name = "foo-bar-baz")]
a: i32,
b: u32,
}
let engine = super::engine();
let mut store = Store::new(&engine, ());
let input = Foo { a: -42, b: 73 };
// Happy path: component type matches field count, names, and types
let component = Component::new(
&engine,
make_echo_component(
r#"(type $Foo (record (field "foo-bar-baz" s32) (field "b" u32)))"#,
8,
),
)?;
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
let output = instance
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")?
.call_and_post_return(&mut store, (input,))?;
assert_eq!(input, output);
// Sad path: field count mismatch (too few)
let component = Component::new(
&engine,
make_echo_component(r#"(type $Foo (record (field "foo-bar-baz" s32)))"#, 4),
)?;
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
assert!(instance
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
.is_err());
// Sad path: field count mismatch (too many)
let component = Component::new(
&engine,
make_echo_component(
r#"(type $Foo (record (field "foo-bar-baz" s32) (field "b" u32) (field "c" u32)))"#,
12,
),
)?;
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
assert!(instance
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
.is_err());
// Sad path: field name mismatch
let component = Component::new(
&engine,
make_echo_component(r#"(type $Foo (record (field "a" s32) (field "b" u32)))"#, 8),
)?;
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
assert!(instance
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
.is_err());
// Sad path: field type mismatch
let component = Component::new(
&engine,
make_echo_component(
r#"(type $Foo (record (field "foo-bar-baz" s32) (field "b" s32)))"#,
8,
),
)?;
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
assert!(instance
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
.is_err());
Ok(())
}