Path: blob/main/tests/all/component_model/macros.rs
1692 views
#![cfg(not(miri))]12use super::{TypedFuncExt, make_echo_component};3use anyhow::Result;4use wasmtime::component::{Component, ComponentType, Lift, Linker, Lower};5use wasmtime::{Engine, Store};6use wasmtime_test_macros::{add_variants, flags_test};78#[test]9fn record_derive() -> Result<()> {10#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]11#[component(record)]12struct Foo {13#[component(name = "foo-bar-baz")]14a: i32,15b: u32,16}1718let engine = super::engine();19let mut store = Store::new(&engine, ());2021// Happy path: component type matches field count, names, and types2223let component = Component::new(24&engine,25make_echo_component(r#"(record (field "foo-bar-baz" s32) (field "b" u32))"#, 8),26)?;27let instance = Linker::new(&engine).instantiate(&mut store, &component)?;2829let input = Foo { a: -42, b: 73 };30let output = instance31.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")?32.call_and_post_return(&mut store, (input,))?;3334assert_eq!((input,), output);3536// Sad path: field count mismatch (too few)3738let component = Component::new(39&engine,40make_echo_component(r#"(record (field "foo-bar-baz" s32))"#, 4),41)?;42let instance = Linker::new(&engine).instantiate(&mut store, &component)?;4344assert!(45instance46.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")47.is_err()48);4950// Sad path: field count mismatch (too many)5152let component = Component::new(53&engine,54make_echo_component(55r#"(record (field "foo-bar-baz" s32) (field "b" u32) (field "c" u32))"#,5612,57),58)?;59let instance = Linker::new(&engine).instantiate(&mut store, &component)?;6061assert!(62instance63.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")64.is_err()65);6667// Sad path: field name mismatch6869let component = Component::new(70&engine,71make_echo_component(r#"(record (field "a" s32) (field "b" u32))"#, 8),72)?;73let instance = Linker::new(&engine).instantiate(&mut store, &component)?;7475assert!(76instance77.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")78.is_err()79);8081// Sad path: field type mismatch8283let component = Component::new(84&engine,85make_echo_component(r#"(record (field "foo-bar-baz" s32) (field "b" s32))"#, 8),86)?;87let instance = Linker::new(&engine).instantiate(&mut store, &component)?;8889assert!(90instance91.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")92.is_err()93);9495// Happy path redux, with generics this time9697#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]98#[component(record)]99struct Generic<A, B> {100#[component(name = "foo-bar-baz")]101a: A,102b: B,103}104105let input = Generic {106a: -43_i32,107b: 74_u32,108};109110let component = Component::new(111&engine,112make_echo_component(r#"(record (field "foo-bar-baz" s32) (field "b" u32))"#, 8),113)?;114let instance = Linker::new(&engine).instantiate(&mut store, &component)?;115116let output = instance117.get_typed_func::<(Generic<i32, u32>,), (Generic<i32, u32>,)>(&mut store, "echo")?118.call_and_post_return(&mut store, (input,))?;119120assert_eq!((input,), output);121122Ok(())123}124125#[test]126fn variant_derive() -> Result<()> {127#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]128#[component(variant)]129enum Foo {130#[component(name = "foo-bar-baz")]131A(i32),132B(u32),133C,134}135136let engine = super::engine();137let mut store = Store::new(&engine, ());138139// Happy path: component type matches case count, names, and types140141let component = Component::new(142&engine,143make_echo_component(144r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C"))"#,1458,146),147)?;148let instance = Linker::new(&engine).instantiate(&mut store, &component)?;149let func = instance.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")?;150151for &input in &[Foo::A(-42), Foo::B(73), Foo::C] {152let output = func.call_and_post_return(&mut store, (input,))?;153154assert_eq!((input,), output);155}156157// Sad path: case count mismatch (too few)158159let component = Component::new(160&engine,161make_echo_component(r#"(variant (case "foo-bar-baz" s32) (case "B" u32))"#, 8),162)?;163let instance = Linker::new(&engine).instantiate(&mut store, &component)?;164165assert!(166instance167.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")168.is_err()169);170171// Sad path: case count mismatch (too many)172173let component = Component::new(174&engine,175make_echo_component(176r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C") (case "D" u32))"#,1778,178),179)?;180let instance = Linker::new(&engine).instantiate(&mut store, &component)?;181182assert!(183instance184.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")185.is_err()186);187188// Sad path: case name mismatch189190let component = Component::new(191&engine,192make_echo_component(r#"(variant (case "A" s32) (case "B" u32) (case "C"))"#, 8),193)?;194let instance = Linker::new(&engine).instantiate(&mut store, &component)?;195196assert!(197instance198.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")199.is_err()200);201202// Sad path: case type mismatch203204let component = Component::new(205&engine,206make_echo_component(207r#"(variant (case "foo-bar-baz" s32) (case "B" s32) (case "C"))"#,2088,209),210)?;211let instance = Linker::new(&engine).instantiate(&mut store, &component)?;212213assert!(214instance215.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")216.is_err()217);218219// Happy path redux, with generics this time220221#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]222#[component(variant)]223enum Generic<A, B> {224#[component(name = "foo-bar-baz")]225A(A),226B(B),227C,228}229230let component = Component::new(231&engine,232make_echo_component(233r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C"))"#,2348,235),236)?;237let instance = Linker::new(&engine).instantiate(&mut store, &component)?;238let func = instance239.get_typed_func::<(Generic<i32, u32>,), (Generic<i32, u32>,)>(&mut store, "echo")?;240241for &input in &[Generic::<i32, u32>::A(-42), Generic::B(73), Generic::C] {242let output = func.call_and_post_return(&mut store, (input,))?;243244assert_eq!((input,), output);245}246247Ok(())248}249250#[test]251fn enum_derive() -> Result<()> {252#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]253#[component(enum)]254#[repr(u8)]255enum Foo {256#[component(name = "foo-bar-baz")]257A,258B,259C,260}261262let engine = super::engine();263let mut store = Store::new(&engine, ());264265// Happy path: component type matches case count and names266267let component = Component::new(268&engine,269make_echo_component(r#"(enum "foo-bar-baz" "B" "C")"#, 4),270)?;271let instance = Linker::new(&engine).instantiate(&mut store, &component)?;272let func = instance.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")?;273274for &input in &[Foo::A, Foo::B, Foo::C] {275let output = func.call_and_post_return(&mut store, (input,))?;276277assert_eq!((input,), output);278}279280// Sad path: case count mismatch (too few)281282let component = Component::new(283&engine,284make_echo_component(r#"(enum "foo-bar-baz" "B")"#, 4),285)?;286let instance = Linker::new(&engine).instantiate(&mut store, &component)?;287288assert!(289instance290.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")291.is_err()292);293294// Sad path: case count mismatch (too many)295296let component = Component::new(297&engine,298make_echo_component(r#"(enum "foo-bar-baz" "B" "C" "D")"#, 4),299)?;300let instance = Linker::new(&engine).instantiate(&mut store, &component)?;301302assert!(303instance304.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")305.is_err()306);307308// Sad path: case name mismatch309310let component = Component::new(&engine, make_echo_component(r#"(enum "A" "B" "C")"#, 4))?;311let instance = Linker::new(&engine).instantiate(&mut store, &component)?;312313assert!(314instance315.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")316.is_err()317);318319// Happy path redux, with large enums (i.e. more than 2^8 cases)320321#[add_variants(257)]322#[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]323#[component(enum)]324#[repr(u16)]325enum Many {}326327let component = Component::new(328&engine,329make_echo_component(330&format!(331"(enum {})",332(0..257)333.map(|index| format!(r#""V{index}""#))334.collect::<Vec<_>>()335.join(" ")336),3374,338),339)?;340let instance = Linker::new(&engine).instantiate(&mut store, &component)?;341let func = instance.get_typed_func::<(Many,), (Many,)>(&mut store, "echo")?;342343for &input in &[Many::V0, Many::V1, Many::V254, Many::V255, Many::V256] {344let output = func.call_and_post_return(&mut store, (input,))?;345346assert_eq!((input,), output);347}348349// TODO: The following case takes forever (i.e. I gave up after 30 minutes) to compile; we'll need to profile350// the compiler to find out why, which may point the way to a more efficient option. On the other hand, this351// may not be worth spending time on. Enums with over 2^16 variants are rare enough.352353// #[add_variants(65537)]354// #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]355// #[component(enum)]356// #[repr(u32)]357// enum ManyMore {}358359Ok(())360}361362#[test]363fn flags() -> Result<()> {364let config = wasmtime_test_util::component::config();365let engine = Engine::new(&config)?;366let mut store = Store::new(&engine, ());367368// Simple 8-bit flags369wasmtime::component::flags! {370Foo {371#[component(name = "foo-bar-baz")]372const A;373const B;374const C;375}376}377378assert_eq!(Foo::default(), (Foo::A | Foo::B) & Foo::C);379assert_eq!(Foo::B, (Foo::A | Foo::B) & Foo::B);380assert_eq!(Foo::A, (Foo::A | Foo::B) & Foo::A);381assert_eq!(Foo::A | Foo::B, Foo::A ^ Foo::B);382assert_eq!(Foo::default(), Foo::A ^ Foo::A);383assert_eq!(Foo::B | Foo::C, !Foo::A);384385// Happy path: component type matches flag count and names386387let component = Component::new(388&engine,389make_echo_component(r#"(flags "foo-bar-baz" "B" "C")"#, 4),390)?;391let instance = Linker::new(&engine).instantiate(&mut store, &component)?;392let func = instance.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")?;393394for n in 0..8 {395let mut input = Foo::default();396if (n & 1) != 0 {397input |= Foo::A;398}399if (n & 2) != 0 {400input |= Foo::B;401}402if (n & 4) != 0 {403input |= Foo::C;404}405406let output = func.call_and_post_return(&mut store, (input,))?;407408assert_eq!((input,), output);409}410411// Sad path: flag count mismatch (too few)412413let component = Component::new(414&engine,415make_echo_component(r#"(flags "foo-bar-baz" "B")"#, 4),416)?;417let instance = Linker::new(&engine).instantiate(&mut store, &component)?;418419assert!(420instance421.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")422.is_err()423);424425// Sad path: flag count mismatch (too many)426427let component = Component::new(428&engine,429make_echo_component(r#"(flags "foo-bar-baz" "B" "C" "D")"#, 4),430)?;431let instance = Linker::new(&engine).instantiate(&mut store, &component)?;432433assert!(434instance435.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")436.is_err()437);438439// Sad path: flag name mismatch440441let component = Component::new(&engine, make_echo_component(r#"(flags "A" "B" "C")"#, 4))?;442let instance = Linker::new(&engine).instantiate(&mut store, &component)?;443444assert!(445instance446.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")447.is_err()448);449450// Happy path redux, with large flag count (exactly 8)451452flags_test!(Foo8Exact, 8);453454assert_eq!(455Foo8Exact::default(),456(Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F7457);458assert_eq!(459Foo8Exact::F6,460(Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F6461);462assert_eq!(463Foo8Exact::F0,464(Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F0465);466assert_eq!(Foo8Exact::F0 | Foo8Exact::F6, Foo8Exact::F0 ^ Foo8Exact::F6);467assert_eq!(Foo8Exact::default(), Foo8Exact::F0 ^ Foo8Exact::F0);468assert_eq!(469Foo8Exact::F1470| Foo8Exact::F2471| Foo8Exact::F3472| Foo8Exact::F4473| Foo8Exact::F5474| Foo8Exact::F6475| Foo8Exact::F7,476!Foo8Exact::F0477);478479let component = Component::new(480&engine,481make_echo_component(482&format!(483r#"(flags {})"#,484(0..8)485.map(|index| format!(r#""F{index}""#))486.collect::<Vec<_>>()487.join(" ")488),4894,490),491)?;492let instance = Linker::new(&engine).instantiate(&mut store, &component)?;493let func = instance.get_typed_func::<(Foo8Exact,), (Foo8Exact,)>(&mut store, "echo")?;494495for &input in &[496Foo8Exact::F0,497Foo8Exact::F1,498Foo8Exact::F5,499Foo8Exact::F6,500Foo8Exact::F7,501] {502let output = func.call_and_post_return(&mut store, (input,))?;503504assert_eq!((input,), output);505}506507// Happy path redux, with large flag count (more than 8)508509flags_test!(Foo16, 9);510511assert_eq!(Foo16::default(), (Foo16::F0 | Foo16::F7) & Foo16::F8);512assert_eq!(Foo16::F7, (Foo16::F0 | Foo16::F7) & Foo16::F7);513assert_eq!(Foo16::F0, (Foo16::F0 | Foo16::F7) & Foo16::F0);514assert_eq!(Foo16::F0 | Foo16::F7, Foo16::F0 ^ Foo16::F7);515assert_eq!(Foo16::default(), Foo16::F0 ^ Foo16::F0);516assert_eq!(517Foo16::F1518| Foo16::F2519| Foo16::F3520| Foo16::F4521| Foo16::F5522| Foo16::F6523| Foo16::F7524| Foo16::F8,525!Foo16::F0526);527528let component = Component::new(529&engine,530make_echo_component(531&format!(532"(flags {})",533(0..9)534.map(|index| format!(r#""F{index}""#))535.collect::<Vec<_>>()536.join(" ")537),5384,539),540)?;541let instance = Linker::new(&engine).instantiate(&mut store, &component)?;542let func = instance.get_typed_func::<(Foo16,), (Foo16,)>(&mut store, "echo")?;543544for &input in &[Foo16::F0, Foo16::F1, Foo16::F6, Foo16::F7, Foo16::F8] {545let output = func.call_and_post_return(&mut store, (input,))?;546547assert_eq!((input,), output);548}549550// Happy path redux, with large flag count (exactly 16)551552flags_test!(Foo16Exact, 16);553554assert_eq!(555Foo16Exact::default(),556(Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F5557);558assert_eq!(559Foo16Exact::F14,560(Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F14561);562assert_eq!(563Foo16Exact::F0,564(Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F0565);566assert_eq!(567Foo16Exact::F0 | Foo16Exact::F14,568Foo16Exact::F0 ^ Foo16Exact::F14569);570assert_eq!(Foo16Exact::default(), Foo16Exact::F0 ^ Foo16Exact::F0);571assert_eq!(572Foo16Exact::F0 | Foo16Exact::F15,573!((!Foo16Exact::F0) & (!Foo16Exact::F15))574);575576let component = Component::new(577&engine,578make_echo_component(579&format!(580r#"(flags {})"#,581(0..16)582.map(|index| format!(r#""F{index}""#))583.collect::<Vec<_>>()584.join(" ")585),5864,587),588)?;589let instance = Linker::new(&engine).instantiate(&mut store, &component)?;590let func = instance.get_typed_func::<(Foo16Exact,), (Foo16Exact,)>(&mut store, "echo")?;591592for &input in &[593Foo16Exact::F0,594Foo16Exact::F1,595Foo16Exact::F13,596Foo16Exact::F14,597Foo16Exact::F15,598] {599let output = func.call_and_post_return(&mut store, (input,))?;600601assert_eq!((input,), output);602}603604// Happy path redux, with large flag count (more than 16)605606flags_test!(Foo32, 17);607608assert_eq!(Foo32::default(), (Foo32::F0 | Foo32::F15) & Foo32::F16);609assert_eq!(Foo32::F15, (Foo32::F0 | Foo32::F15) & Foo32::F15);610assert_eq!(Foo32::F0, (Foo32::F0 | Foo32::F15) & Foo32::F0);611assert_eq!(Foo32::F0 | Foo32::F15, Foo32::F0 ^ Foo32::F15);612assert_eq!(Foo32::default(), Foo32::F0 ^ Foo32::F0);613assert_eq!(Foo32::F0 | Foo32::F16, !((!Foo32::F0) & (!Foo32::F16)));614615let component = Component::new(616&engine,617make_echo_component(618&format!(619"(flags {})",620(0..17)621.map(|index| format!(r#""F{index}""#))622.collect::<Vec<_>>()623.join(" ")624),6254,626),627)?;628let instance = Linker::new(&engine).instantiate(&mut store, &component)?;629let func = instance.get_typed_func::<(Foo32,), (Foo32,)>(&mut store, "echo")?;630631for &input in &[Foo32::F0, Foo32::F1, Foo32::F14, Foo32::F15, Foo32::F16] {632let output = func.call_and_post_return(&mut store, (input,))?;633634assert_eq!((input,), output);635}636637// Happy path redux, with large flag count (exactly 32)638639flags_test!(Foo32Exact, 32);640641assert_eq!(642Foo32Exact::default(),643(Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F31644);645assert_eq!(646Foo32Exact::F30,647(Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F30648);649assert_eq!(650Foo32Exact::F0,651(Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F0652);653assert_eq!(654Foo32Exact::F0 | Foo32Exact::F30,655Foo32Exact::F0 ^ Foo32Exact::F30656);657assert_eq!(Foo32Exact::default(), Foo32Exact::F0 ^ Foo32Exact::F0);658assert_eq!(659Foo32Exact::F0 | Foo32Exact::F15,660!((!Foo32Exact::F0) & (!Foo32Exact::F15))661);662663let component = Component::new(664&engine,665make_echo_component(666&format!(667r#"(flags {})"#,668(0..32)669.map(|index| format!(r#""F{index}""#))670.collect::<Vec<_>>()671.join(" ")672),6734,674),675)?;676let instance = Linker::new(&engine).instantiate(&mut store, &component)?;677let func = instance.get_typed_func::<(Foo32Exact,), (Foo32Exact,)>(&mut store, "echo")?;678679for &input in &[680Foo32Exact::F0,681Foo32Exact::F1,682Foo32Exact::F29,683Foo32Exact::F30,684Foo32Exact::F31,685] {686let output = func.call_and_post_return(&mut store, (input,))?;687688assert_eq!((input,), output);689}690691Ok(())692}693694695