Files
wasmtime/tests/all/component_model/macros.rs
Joel Dice e31ff9dc67 implement wasmtime::component::flags! per #4308 (#4414)
* implement wasmtime::component::flags! per #4308

This is the last macro needed to complete #4308.  It supports generating a Rust
type that represents a `flags` component type, analogous to how the [bitflags
crate](https://crates.io/crates/bitflags) operates.

Signed-off-by: Joel Dice <joel.dice@fermyon.com>

* wrap `format_flags` output in parens

This ensures we generate non-empty output even when no flags are set.  Empty
output for a `Debug` implementation would be confusing.

Signed-off-by: Joel Dice <joel.dice@fermyon.com>

* unconditionally derive `Lift` and `Lower` in wasmtime::component::flags!

Per feedback on #4414, we now derive impls for those traits unconditionally,
which simplifies the syntax of the macro.

Also, I happened to notice an alignment bug in `LowerExpander::expand_variant`,
so I fixed that and cleaned up some related code.

Finally, I used @jameysharp's trick to calculate bit masks without looping.

Signed-off-by: Joel Dice <joel.dice@fermyon.com>

* fix shift overflow regression in previous commit

Jamey pointed out my mistake: I didn't consider the case when the flag count was
evenly divisible by the representation size.  This fixes the problem and adds
test cases to cover it.

Signed-off-by: Joel Dice <joel.dice@fermyon.com>
2022-07-12 16:47:58 -07:00

912 lines
26 KiB
Rust

use super::TypedFuncExt;
use anyhow::Result;
use component_macro_test::{add_variants, flags_test};
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, ());
// 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 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#"(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());
// 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#"(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::<(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(r#"(type $Foo (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(r#"(type $Foo (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#"(type $Foo (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(r#"(type $Foo (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(r#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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!(
r#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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#"(type $Foo (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!(
r#"(type $Foo (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#"(type $Foo (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!(
r#"(type $Foo (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#"(type $Foo (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!(
r#"(type $Foo (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!(
r#"(type $Foo (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(())
}