* support dynamic function calls in component model This addresses #4310, introducing a new `component::values::Val` type for representing component values dynamically, as well as `component::types::Type` for representing the corresponding interface types. It also adds a `call` method to `component::func::Func`, which takes a slice of `Val`s as parameters and returns a `Result<Val>` representing the result. Note that I've moved `post_return` and `call_raw` from `TypedFunc` to `Func` since there was nothing specific to `TypedFunc` about them, and I wanted to reuse them. The code in both is unchanged beyond the trivial tweaks to make them fit in their new home. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * order variants and match cases more consistently Signed-off-by: Joel Dice <joel.dice@fermyon.com> * implement lift for String, Box<str>, etc. This also removes the redundant `store` parameter from `Type::load`. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * implement code review feedback This fixes a few issues: - Bad offset calculation when lowering - Missing variant padding - Style issues regarding `types::Handle` - Missed opportunities to reuse `Lift` and `Lower` impls It also adds forwarding `Lift` impls for `Box<[T]>`, `Vec<T>`, etc. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * move `new_*` methods to specific `types` structs Per review feedback, I've moved `Type::new_record` to `Record::new_val` and added a `Type::unwrap_record` method; likewise for the other kinds of types. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * make tuple, option, and expected type comparisons recursive These types should compare as equal across component boundaries as long as their type parameters are equal. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * improve error diagnostic in `Type::check` We now distinguish between more failure cases to provide an informative error message. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * address review feedback - Remove `WasmStr::to_str_from_memory` and `WasmList::get_from_memory` - add `try_new` methods to various `values` types - avoid using `ExactSizeIterator::len` where we can't trust it - fix over-constrained bounds on forwarded `ComponentType` impls Signed-off-by: Joel Dice <joel.dice@fermyon.com> * rearrange code per review feedback - Move functions from `types` to `values` module so we can make certain struct fields private - Rename `try_new` to just `new` Signed-off-by: Joel Dice <joel.dice@fermyon.com> * remove special-case equality test for tuples, options, and expecteds Instead, I've added a FIXME comment and will open an issue to do recursive structural equality testing. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
816 lines
24 KiB
Rust
816 lines
24 KiB
Rust
use super::{make_echo_component, TypedFuncExt};
|
|
use anyhow::Result;
|
|
use component_macro_test::{add_variants, flags_test};
|
|
use wasmtime::component::{Component, ComponentType, Lift, Linker, Lower};
|
|
use wasmtime::Store;
|
|
|
|
#[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, ());
|
|
|
|
// Happy path: component type matches field count, names, and types
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(r#"(record (field "foo-bar-baz" s32) (field "b" u32))"#, 8),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
|
|
let input = Foo { a: -42, b: 73 };
|
|
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#"(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#"(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#"(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#"(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());
|
|
|
|
// Happy path redux, with generics this time
|
|
|
|
#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
|
|
#[component(record)]
|
|
struct Generic<A, B> {
|
|
#[component(name = "foo-bar-baz")]
|
|
a: A,
|
|
b: B,
|
|
}
|
|
|
|
let input = Generic {
|
|
a: -43_i32,
|
|
b: 74_u32,
|
|
};
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(r#"(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::<(Generic<i32, u32>,), Generic<i32, u32>, _>(&mut store, "echo")?
|
|
.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn union_derive() -> Result<()> {
|
|
#[derive(ComponentType, Lift, Lower, PartialEq, Debug, Copy, Clone)]
|
|
#[component(union)]
|
|
enum Foo {
|
|
A(i32),
|
|
B(u32),
|
|
C(i32),
|
|
}
|
|
|
|
let engine = super::engine();
|
|
let mut store = Store::new(&engine, ());
|
|
|
|
// Happy path: component type matches case count and types
|
|
|
|
let component = Component::new(&engine, make_echo_component("(union s32 u32 s32)", 8))?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[Foo::A(-42), Foo::B(73), Foo::C(314159265)] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
// Sad path: case count mismatch (too few)
|
|
|
|
let component = Component::new(&engine, make_echo_component("(union s32 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: case count mismatch (too many)
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(r#"(union s32 u32 s32 s32)"#, 8),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
|
|
assert!(instance
|
|
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
|
|
.is_err());
|
|
|
|
assert!(instance
|
|
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
|
|
.is_err());
|
|
|
|
// Sad path: case type mismatch
|
|
|
|
let component = Component::new(&engine, make_echo_component("(union s32 s32 s32)", 8))?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
|
|
assert!(instance
|
|
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
|
|
.is_err());
|
|
|
|
// Happy path redux, with generics this time
|
|
|
|
#[derive(ComponentType, Lift, Lower, PartialEq, Debug, Copy, Clone)]
|
|
#[component(union)]
|
|
enum Generic<A, B, C> {
|
|
A(A),
|
|
B(B),
|
|
C(C),
|
|
}
|
|
|
|
let component = Component::new(&engine, make_echo_component("(union s32 u32 s32)", 8))?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Generic<i32, u32, i32>,), Generic<i32, u32, i32>, _>(
|
|
&mut store, "echo",
|
|
)?;
|
|
|
|
for &input in &[
|
|
Generic::<i32, u32, i32>::A(-42),
|
|
Generic::B(73),
|
|
Generic::C(314159265),
|
|
] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn variant_derive() -> Result<()> {
|
|
#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
|
|
#[component(variant)]
|
|
enum Foo {
|
|
#[component(name = "foo-bar-baz")]
|
|
A(i32),
|
|
B(u32),
|
|
C,
|
|
}
|
|
|
|
let engine = super::engine();
|
|
let mut store = Store::new(&engine, ());
|
|
|
|
// Happy path: component type matches case count, names, and types
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C" unit))"#,
|
|
8,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[Foo::A(-42), Foo::B(73), Foo::C] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
// Sad path: case count mismatch (too few)
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(r#"(variant (case "foo-bar-baz" s32) (case "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: case count mismatch (too many)
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C" unit) (case "D" 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: case name mismatch
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
r#"(variant (case "A" s32) (case "B" u32) (case "C" unit))"#,
|
|
8,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
|
|
assert!(instance
|
|
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
|
|
.is_err());
|
|
|
|
// Sad path: case type mismatch
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
r#"(variant (case "foo-bar-baz" s32) (case "B" s32) (case "C" unit))"#,
|
|
8,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
|
|
assert!(instance
|
|
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
|
|
.is_err());
|
|
|
|
// Happy path redux, with generics this time
|
|
|
|
#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
|
|
#[component(variant)]
|
|
enum Generic<A, B> {
|
|
#[component(name = "foo-bar-baz")]
|
|
A(A),
|
|
B(B),
|
|
C,
|
|
}
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C" unit))"#,
|
|
8,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance
|
|
.get_typed_func::<(Generic<i32, u32>,), Generic<i32, u32>, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[Generic::<i32, u32>::A(-42), Generic::B(73), Generic::C] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn enum_derive() -> Result<()> {
|
|
#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
|
|
#[component(enum)]
|
|
enum Foo {
|
|
#[component(name = "foo-bar-baz")]
|
|
A,
|
|
B,
|
|
C,
|
|
}
|
|
|
|
let engine = super::engine();
|
|
let mut store = Store::new(&engine, ());
|
|
|
|
// Happy path: component type matches case count and names
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(r#"(enum "foo-bar-baz" "B" "C")"#, 4),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[Foo::A, Foo::B, Foo::C] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
// Sad path: case count mismatch (too few)
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(r#"(enum "foo-bar-baz" "B")"#, 4),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
|
|
assert!(instance
|
|
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
|
|
.is_err());
|
|
|
|
// Sad path: case count mismatch (too many)
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(r#"(enum "foo-bar-baz" "B" "C" "D")"#, 4),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
|
|
assert!(instance
|
|
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
|
|
.is_err());
|
|
|
|
// Sad path: case name mismatch
|
|
|
|
let component = Component::new(&engine, make_echo_component(r#"(enum "A" "B" "C")"#, 4))?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
|
|
assert!(instance
|
|
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
|
|
.is_err());
|
|
|
|
// Happy path redux, with large enums (i.e. more than 2^8 cases)
|
|
|
|
#[add_variants(257)]
|
|
#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
|
|
#[component(enum)]
|
|
enum Many {}
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
&format!(
|
|
"(enum {})",
|
|
(0..257)
|
|
.map(|index| format!(r#""V{}""#, index))
|
|
.collect::<Vec<_>>()
|
|
.join(" ")
|
|
),
|
|
4,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Many,), Many, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[Many::V0, Many::V1, Many::V254, Many::V255, Many::V256] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
// TODO: The following case takes forever (i.e. I gave up after 30 minutes) to compile; we'll need to profile
|
|
// the compiler to find out why, which may point the way to a more efficient option. On the other hand, this
|
|
// may not be worth spending time on. Enums with over 2^16 variants are rare enough.
|
|
|
|
// #[add_variants(65537)]
|
|
// #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
|
|
// #[component(enum)]
|
|
// enum ManyMore {}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn flags() -> Result<()> {
|
|
wasmtime::component::flags! {
|
|
Foo {
|
|
#[component(name = "foo-bar-baz")]
|
|
const A;
|
|
const B;
|
|
const C;
|
|
}
|
|
}
|
|
|
|
assert_eq!(Foo::default(), (Foo::A | Foo::B) & Foo::C);
|
|
assert_eq!(Foo::B, (Foo::A | Foo::B) & Foo::B);
|
|
assert_eq!(Foo::A, (Foo::A | Foo::B) & Foo::A);
|
|
assert_eq!(Foo::A | Foo::B, Foo::A ^ Foo::B);
|
|
assert_eq!(Foo::default(), Foo::A ^ Foo::A);
|
|
assert_eq!(Foo::B | Foo::C, !Foo::A);
|
|
|
|
let engine = super::engine();
|
|
let mut store = Store::new(&engine, ());
|
|
|
|
// Happy path: component type matches flag count and names
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(r#"(flags "foo-bar-baz" "B" "C")"#, 4),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")?;
|
|
|
|
for n in 0..8 {
|
|
let mut input = Foo::default();
|
|
if (n & 1) != 0 {
|
|
input |= Foo::A;
|
|
}
|
|
if (n & 2) != 0 {
|
|
input |= Foo::B;
|
|
}
|
|
if (n & 4) != 0 {
|
|
input |= Foo::C;
|
|
}
|
|
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
// Sad path: flag count mismatch (too few)
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(r#"(flags "foo-bar-baz" "B")"#, 4),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
|
|
assert!(instance
|
|
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
|
|
.is_err());
|
|
|
|
// Sad path: flag count mismatch (too many)
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(r#"(flags "foo-bar-baz" "B" "C" "D")"#, 4),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
|
|
assert!(instance
|
|
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
|
|
.is_err());
|
|
|
|
// Sad path: flag name mismatch
|
|
|
|
let component = Component::new(&engine, make_echo_component(r#"(flags "A" "B" "C")"#, 4))?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
|
|
assert!(instance
|
|
.get_typed_func::<(Foo,), Foo, _>(&mut store, "echo")
|
|
.is_err());
|
|
|
|
// Happy path redux, with large flag count (exactly 8)
|
|
|
|
flags_test!(Foo8Exact, 8);
|
|
|
|
assert_eq!(
|
|
Foo8Exact::default(),
|
|
(Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F7
|
|
);
|
|
assert_eq!(
|
|
Foo8Exact::F6,
|
|
(Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F6
|
|
);
|
|
assert_eq!(
|
|
Foo8Exact::F0,
|
|
(Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F0
|
|
);
|
|
assert_eq!(Foo8Exact::F0 | Foo8Exact::F6, Foo8Exact::F0 ^ Foo8Exact::F6);
|
|
assert_eq!(Foo8Exact::default(), Foo8Exact::F0 ^ Foo8Exact::F0);
|
|
assert_eq!(
|
|
Foo8Exact::F1
|
|
| Foo8Exact::F2
|
|
| Foo8Exact::F3
|
|
| Foo8Exact::F4
|
|
| Foo8Exact::F5
|
|
| Foo8Exact::F6
|
|
| Foo8Exact::F7,
|
|
!Foo8Exact::F0
|
|
);
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
&format!(
|
|
r#"(flags {})"#,
|
|
(0..8)
|
|
.map(|index| format!(r#""F{}""#, index))
|
|
.collect::<Vec<_>>()
|
|
.join(" ")
|
|
),
|
|
4,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Foo8Exact,), Foo8Exact, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[
|
|
Foo8Exact::F0,
|
|
Foo8Exact::F1,
|
|
Foo8Exact::F5,
|
|
Foo8Exact::F6,
|
|
Foo8Exact::F7,
|
|
] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
// Happy path redux, with large flag count (more than 8)
|
|
|
|
flags_test!(Foo16, 9);
|
|
|
|
assert_eq!(Foo16::default(), (Foo16::F0 | Foo16::F7) & Foo16::F8);
|
|
assert_eq!(Foo16::F7, (Foo16::F0 | Foo16::F7) & Foo16::F7);
|
|
assert_eq!(Foo16::F0, (Foo16::F0 | Foo16::F7) & Foo16::F0);
|
|
assert_eq!(Foo16::F0 | Foo16::F7, Foo16::F0 ^ Foo16::F7);
|
|
assert_eq!(Foo16::default(), Foo16::F0 ^ Foo16::F0);
|
|
assert_eq!(
|
|
Foo16::F1
|
|
| Foo16::F2
|
|
| Foo16::F3
|
|
| Foo16::F4
|
|
| Foo16::F5
|
|
| Foo16::F6
|
|
| Foo16::F7
|
|
| Foo16::F8,
|
|
!Foo16::F0
|
|
);
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
&format!(
|
|
"(flags {})",
|
|
(0..9)
|
|
.map(|index| format!(r#""F{}""#, index))
|
|
.collect::<Vec<_>>()
|
|
.join(" ")
|
|
),
|
|
4,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Foo16,), Foo16, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[Foo16::F0, Foo16::F1, Foo16::F6, Foo16::F7, Foo16::F8] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
// Happy path redux, with large flag count (exactly 16)
|
|
|
|
flags_test!(Foo16Exact, 16);
|
|
|
|
assert_eq!(
|
|
Foo16Exact::default(),
|
|
(Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F5
|
|
);
|
|
assert_eq!(
|
|
Foo16Exact::F14,
|
|
(Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F14
|
|
);
|
|
assert_eq!(
|
|
Foo16Exact::F0,
|
|
(Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F0
|
|
);
|
|
assert_eq!(
|
|
Foo16Exact::F0 | Foo16Exact::F14,
|
|
Foo16Exact::F0 ^ Foo16Exact::F14
|
|
);
|
|
assert_eq!(Foo16Exact::default(), Foo16Exact::F0 ^ Foo16Exact::F0);
|
|
assert_eq!(
|
|
Foo16Exact::F0 | Foo16Exact::F15,
|
|
!((!Foo16Exact::F0) & (!Foo16Exact::F15))
|
|
);
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
&format!(
|
|
r#"(flags {})"#,
|
|
(0..16)
|
|
.map(|index| format!(r#""F{}""#, index))
|
|
.collect::<Vec<_>>()
|
|
.join(" ")
|
|
),
|
|
4,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Foo16Exact,), Foo16Exact, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[
|
|
Foo16Exact::F0,
|
|
Foo16Exact::F1,
|
|
Foo16Exact::F13,
|
|
Foo16Exact::F14,
|
|
Foo16Exact::F15,
|
|
] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
// Happy path redux, with large flag count (more than 16)
|
|
|
|
flags_test!(Foo32, 17);
|
|
|
|
assert_eq!(Foo32::default(), (Foo32::F0 | Foo32::F15) & Foo32::F16);
|
|
assert_eq!(Foo32::F15, (Foo32::F0 | Foo32::F15) & Foo32::F15);
|
|
assert_eq!(Foo32::F0, (Foo32::F0 | Foo32::F15) & Foo32::F0);
|
|
assert_eq!(Foo32::F0 | Foo32::F15, Foo32::F0 ^ Foo32::F15);
|
|
assert_eq!(Foo32::default(), Foo32::F0 ^ Foo32::F0);
|
|
assert_eq!(Foo32::F0 | Foo32::F16, !((!Foo32::F0) & (!Foo32::F16)));
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
&format!(
|
|
"(flags {})",
|
|
(0..17)
|
|
.map(|index| format!(r#""F{}""#, index))
|
|
.collect::<Vec<_>>()
|
|
.join(" ")
|
|
),
|
|
4,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Foo32,), Foo32, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[Foo32::F0, Foo32::F1, Foo32::F14, Foo32::F15, Foo32::F16] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
// Happy path redux, with large flag count (exactly 32)
|
|
|
|
flags_test!(Foo32Exact, 32);
|
|
|
|
assert_eq!(
|
|
Foo32Exact::default(),
|
|
(Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F31
|
|
);
|
|
assert_eq!(
|
|
Foo32Exact::F30,
|
|
(Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F30
|
|
);
|
|
assert_eq!(
|
|
Foo32Exact::F0,
|
|
(Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F0
|
|
);
|
|
assert_eq!(
|
|
Foo32Exact::F0 | Foo32Exact::F30,
|
|
Foo32Exact::F0 ^ Foo32Exact::F30
|
|
);
|
|
assert_eq!(Foo32Exact::default(), Foo32Exact::F0 ^ Foo32Exact::F0);
|
|
assert_eq!(
|
|
Foo32Exact::F0 | Foo32Exact::F15,
|
|
!((!Foo32Exact::F0) & (!Foo32Exact::F15))
|
|
);
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
&format!(
|
|
r#"(flags {})"#,
|
|
(0..32)
|
|
.map(|index| format!(r#""F{}""#, index))
|
|
.collect::<Vec<_>>()
|
|
.join(" ")
|
|
),
|
|
4,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Foo32Exact,), Foo32Exact, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[
|
|
Foo32Exact::F0,
|
|
Foo32Exact::F1,
|
|
Foo32Exact::F29,
|
|
Foo32Exact::F30,
|
|
Foo32Exact::F31,
|
|
] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
// Happy path redux, with large flag count (more than 32)
|
|
|
|
flags_test!(Foo64, 33);
|
|
|
|
assert_eq!(Foo64::default(), (Foo64::F0 | Foo64::F31) & Foo64::F32);
|
|
assert_eq!(Foo64::F31, (Foo64::F0 | Foo64::F31) & Foo64::F31);
|
|
assert_eq!(Foo64::F0, (Foo64::F0 | Foo64::F31) & Foo64::F0);
|
|
assert_eq!(Foo64::F0 | Foo64::F31, Foo64::F0 ^ Foo64::F31);
|
|
assert_eq!(Foo64::default(), Foo64::F0 ^ Foo64::F0);
|
|
assert_eq!(Foo64::F0 | Foo64::F32, !((!Foo64::F0) & (!Foo64::F32)));
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
&format!(
|
|
"(flags {})",
|
|
(0..33)
|
|
.map(|index| format!(r#""F{}""#, index))
|
|
.collect::<Vec<_>>()
|
|
.join(" ")
|
|
),
|
|
8,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Foo64,), Foo64, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[Foo64::F0, Foo64::F1, Foo64::F30, Foo64::F31, Foo64::F32] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
// Happy path redux, with large flag count (more than 64)
|
|
|
|
flags_test!(Foo96, 65);
|
|
|
|
assert_eq!(Foo96::default(), (Foo96::F0 | Foo96::F63) & Foo96::F64);
|
|
assert_eq!(Foo96::F63, (Foo96::F0 | Foo96::F63) & Foo96::F63);
|
|
assert_eq!(Foo96::F0, (Foo96::F0 | Foo96::F63) & Foo96::F0);
|
|
assert_eq!(Foo96::F0 | Foo96::F63, Foo96::F0 ^ Foo96::F63);
|
|
assert_eq!(Foo96::default(), Foo96::F0 ^ Foo96::F0);
|
|
assert_eq!(Foo96::F0 | Foo96::F64, !((!Foo96::F0) & (!Foo96::F64)));
|
|
|
|
let component = Component::new(
|
|
&engine,
|
|
make_echo_component(
|
|
&format!(
|
|
"(flags {})",
|
|
(0..65)
|
|
.map(|index| format!(r#""F{}""#, index))
|
|
.collect::<Vec<_>>()
|
|
.join(" ")
|
|
),
|
|
12,
|
|
),
|
|
)?;
|
|
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
|
|
let func = instance.get_typed_func::<(Foo96,), Foo96, _>(&mut store, "echo")?;
|
|
|
|
for &input in &[Foo96::F0, Foo96::F1, Foo96::F62, Foo96::F63, Foo96::F64] {
|
|
let output = func.call_and_post_return(&mut store, (input,))?;
|
|
|
|
assert_eq!(input, output);
|
|
}
|
|
|
|
Ok(())
|
|
}
|