Path: blob/main/tests/all/component_model/dynamic.rs
3069 views
#![cfg(not(miri))]12use super::{Param, Type, make_echo_component, make_echo_component_with_params};3use wasmtime::Result;4use wasmtime::component::types::{self, Case, ComponentItem, Field};5use wasmtime::component::{Component, Linker, ResourceType, Val};6use wasmtime::{Module, Store};7use wasmtime_component_util::REALLOC_AND_FREE;89#[test]10fn primitives() -> Result<()> {11let engine = super::engine();12let mut store = Store::new(&engine, ());13let mut output = [Val::Bool(false)];1415for (input, ty, param) in [16(Val::Bool(true), "bool", Param(Type::U8, Some(0))),17(Val::S8(-42), "s8", Param(Type::S8, Some(0))),18(Val::U8(42), "u8", Param(Type::U8, Some(0))),19(Val::S16(-4242), "s16", Param(Type::S16, Some(0))),20(Val::U16(4242), "u16", Param(Type::U16, Some(0))),21(Val::S32(-314159265), "s32", Param(Type::I32, Some(0))),22(Val::U32(314159265), "u32", Param(Type::I32, Some(0))),23(Val::S64(-31415926535897), "s64", Param(Type::I64, Some(0))),24(Val::U64(31415926535897), "u64", Param(Type::I64, Some(0))),25(26Val::Float32(3.14159265),27"float32",28Param(Type::F32, Some(0)),29),30(31Val::Float64(3.14159265),32"float64",33Param(Type::F64, Some(0)),34),35(Val::Char('��'), "char", Param(Type::I32, Some(0))),36] {37let component = Component::new(&engine, make_echo_component_with_params(ty, &[param]))?;38let instance = Linker::new(&engine).instantiate(&mut store, &component)?;39let func = instance.get_func(&mut store, "echo").unwrap();40func.call(&mut store, &[input.clone()], &mut output)?;4142assert_eq!(input, output[0]);43}4445// Sad path: type mismatch4647let component = Component::new(48&engine,49make_echo_component_with_params("float64", &[Param(Type::F64, Some(0))]),50)?;51let instance = Linker::new(&engine).instantiate(&mut store, &component)?;52let func = instance.get_func(&mut store, "echo").unwrap();53let err = func54.call(&mut store, &[Val::U64(42)], &mut output)55.unwrap_err();5657assert!(err.to_string().contains("type mismatch"), "{err}");5859// Sad path: arity mismatch (too many)6061let err = func62.call(63&mut store,64&[Val::Float64(3.14159265), Val::Float64(3.14159265)],65&mut output,66)67.unwrap_err();6869assert!(70err.to_string().contains("expected 1 argument(s), got 2"),71"{err}"72);7374// Sad path: arity mismatch (too few)7576let err = func.call(&mut store, &[], &mut output).unwrap_err();77assert!(78err.to_string().contains("expected 1 argument(s), got 0"),79"{err}"80);8182let err = func.call(&mut store, &output, &mut []).unwrap_err();83assert!(84err.to_string().contains("expected 1 result(s), got 0"),85"{err}"86);8788Ok(())89}9091#[test]92fn strings() -> Result<()> {93let engine = super::engine();94let mut store = Store::new(&engine, ());9596let component = Component::new(&engine, make_echo_component("string", 8))?;97let instance = Linker::new(&engine).instantiate(&mut store, &component)?;98let func = instance.get_func(&mut store, "echo").unwrap();99let input = Val::String("hello, component!".into());100let mut output = [Val::Bool(false)];101func.call(&mut store, &[input.clone()], &mut output)?;102assert_eq!(input, output[0]);103104Ok(())105}106107#[test]108fn lists() -> Result<()> {109let engine = super::engine();110let mut store = Store::new(&engine, ());111112let component = Component::new(&engine, make_echo_component("(list u32)", 8))?;113let instance = Linker::new(&engine).instantiate(&mut store, &component)?;114let func = instance.get_func(&mut store, "echo").unwrap();115let input = Val::List(vec![116Val::U32(32343),117Val::U32(79023439),118Val::U32(2084037802),119]);120let mut output = [Val::Bool(false)];121func.call(&mut store, &[input.clone()], &mut output)?;122123assert_eq!(input, output[0]);124125// Sad path: type mismatch126127let err = Val::List(vec![128Val::U32(32343),129Val::U32(79023439),130Val::Float32(3.14159265),131]);132let err = func.call(&mut store, &[err], &mut output).unwrap_err();133assert!(err.to_string().contains("type mismatch"), "{err}");134135Ok(())136}137138#[test]139fn records() -> Result<()> {140let engine = super::engine();141let mut store = Store::new(&engine, ());142143let component = Component::new(144&engine,145make_echo_component_with_params(146r#"147(type $c' (record148(field "D" bool)149(field "E" u32)150))151(export $c "c" (type $c'))152(type $Foo' (record153(field "A" u32)154(field "B" float64)155(field "C" $c)156))157"#,158&[159Param(Type::I32, Some(0)),160Param(Type::F64, Some(8)),161Param(Type::U8, Some(16)),162Param(Type::I32, Some(20)),163],164),165)?;166let instance = Linker::new(&engine).instantiate(&mut store, &component)?;167let func = instance.get_func(&mut store, "echo").unwrap();168let input = Val::Record(vec![169("A".into(), Val::U32(32343)),170("B".into(), Val::Float64(3.14159265)),171(172"C".into(),173Val::Record(vec![174("D".into(), Val::Bool(false)),175("E".into(), Val::U32(2084037802)),176]),177),178]);179let mut output = [Val::Bool(false)];180func.call(&mut store, &[input.clone()], &mut output)?;181182assert_eq!(input, output[0]);183184// Sad path: type mismatch185186let err = Val::Record(vec![187("A".into(), Val::S32(32343)),188("B".into(), Val::Float64(3.14159265)),189(190"C".into(),191Val::Record(vec![192("D".into(), Val::Bool(false)),193("E".into(), Val::U32(2084037802)),194]),195),196]);197let instance = Linker::new(&engine).instantiate(&mut store, &component)?;198let func = instance.get_func(&mut store, "echo").unwrap();199let err = func.call(&mut store, &[err], &mut output).unwrap_err();200assert!(err.to_string().contains("type mismatch"), "{err}");201202// Sad path: too many fields203204let err = Val::Record(vec![205("A".into(), Val::U32(32343)),206("B".into(), Val::Float64(3.14159265)),207(208"C".into(),209Val::Record(vec![210("D".into(), Val::Bool(false)),211("E".into(), Val::U32(2084037802)),212]),213),214("F".into(), Val::Bool(true)),215]);216let instance = Linker::new(&engine).instantiate(&mut store, &component)?;217let func = instance.get_func(&mut store, "echo").unwrap();218let err = func.call(&mut store, &[err], &mut output).unwrap_err();219assert!(220err.to_string().contains("expected 3 fields, got 4"),221"{err}"222);223224// Sad path: too few fields225226let err = Val::Record(vec![227("A".into(), Val::U32(32343)),228("B".into(), Val::Float64(3.14159265)),229]);230let instance = Linker::new(&engine).instantiate(&mut store, &component)?;231let func = instance.get_func(&mut store, "echo").unwrap();232let err = func.call(&mut store, &[err], &mut output).unwrap_err();233assert!(234err.to_string().contains("expected 3 fields, got 2"),235"{err}"236);237238Ok(())239}240241#[test]242fn variants() -> Result<()> {243let engine = super::engine();244let mut store = Store::new(&engine, ());245246let fragment = r#"247(type $c' (record (field "D" bool) (field "E" u32)))248(export $c "c" (type $c'))249(type $Foo' (variant250(case "A" u32)251(case "B" float64)252(case "C" $c)253))254"#;255256let component = Component::new(257&engine,258make_echo_component_with_params(259fragment,260&[261Param(Type::U8, Some(0)),262Param(Type::I64, Some(8)),263Param(Type::I32, None),264],265),266)?;267let instance = Linker::new(&engine).instantiate(&mut store, &component)?;268let func = instance.get_func(&mut store, "echo").unwrap();269let input = Val::Variant("B".into(), Some(Box::new(Val::Float64(3.14159265))));270let mut output = [Val::Bool(false)];271func.call(&mut store, &[input.clone()], &mut output)?;272273assert_eq!(input, output[0]);274275// Do it again, this time using case "C"276277let component = Component::new(278&engine,279make_echo_component_with_params(280fragment,281&[282Param(Type::U8, Some(0)),283Param(Type::I64, Some(8)),284Param(Type::I32, Some(12)),285],286),287)?;288let instance = Linker::new(&engine).instantiate(&mut store, &component)?;289let func = instance.get_func(&mut store, "echo").unwrap();290let input = Val::Variant(291"C".into(),292Some(Box::new(Val::Record(vec![293("D".into(), Val::Bool(true)),294("E".into(), Val::U32(314159265)),295]))),296);297func.call(&mut store, &[input.clone()], &mut output)?;298299assert_eq!(input, output[0]);300301// Sad path: type mismatch302303let instance = Linker::new(&engine).instantiate(&mut store, &component)?;304let func = instance.get_func(&mut store, "echo").unwrap();305let err = Val::Variant("B".into(), Some(Box::new(Val::U64(314159265))));306let err = func.call(&mut store, &[err], &mut output).unwrap_err();307assert!(err.to_string().contains("type mismatch"), "{err}");308309let instance = Linker::new(&engine).instantiate(&mut store, &component)?;310let func = instance.get_func(&mut store, "echo").unwrap();311let err = Val::Variant("B".into(), None);312let err = func.call(&mut store, &[err], &mut output).unwrap_err();313assert!(314err.to_string().contains("expected a payload for case `B`"),315"{err}"316);317318// Sad path: unknown case319320let instance = Linker::new(&engine).instantiate(&mut store, &component)?;321let func = instance.get_func(&mut store, "echo").unwrap();322let err = Val::Variant("D".into(), Some(Box::new(Val::U64(314159265))));323let err = func.call(&mut store, &[err], &mut output).unwrap_err();324assert!(err.to_string().contains("unknown variant case"), "{err}");325326let instance = Linker::new(&engine).instantiate(&mut store, &component)?;327let func = instance.get_func(&mut store, "echo").unwrap();328let err = Val::Variant("D".into(), None);329let err = func.call(&mut store, &[err], &mut output).unwrap_err();330assert!(err.to_string().contains("unknown variant case"), "{err}");331332// Make sure we lift variants which have cases of different sizes with the correct alignment333334let component = Component::new(335&engine,336make_echo_component_with_params(337r#"338(type $c' (record (field "D" bool) (field "E" u32)))339(export $c "c" (type $c'))340(type $a' (variant341(case "A" u32)342(case "B" float64)343(case "C" $c)344))345(export $a "a" (type $a'))346(type $Foo' (record347(field "A" $a)348(field "B" u32)349))350"#,351&[352Param(Type::U8, Some(0)),353Param(Type::I64, Some(8)),354Param(Type::I32, None),355Param(Type::I32, Some(16)),356],357),358)?;359let instance = Linker::new(&engine).instantiate(&mut store, &component)?;360let func = instance.get_func(&mut store, "echo").unwrap();361let input = Val::Record(vec![362(363"A".into(),364Val::Variant("A".into(), Some(Box::new(Val::U32(314159265)))),365),366("B".into(), Val::U32(628318530)),367]);368func.call(&mut store, &[input.clone()], &mut output)?;369370assert_eq!(input, output[0]);371372Ok(())373}374375#[test]376fn flags() -> Result<()> {377let engine = super::engine();378let mut store = Store::new(&engine, ());379380let component = Component::new(381&engine,382make_echo_component_with_params(383r#"(flags "A" "B" "C" "D" "E")"#,384&[Param(Type::U8, Some(0))],385),386)?;387let instance = Linker::new(&engine).instantiate(&mut store, &component)?;388let func = instance.get_func(&mut store, "echo").unwrap();389let input = Val::Flags(vec!["B".into(), "D".into()]);390let mut output = [Val::Bool(false)];391func.call(&mut store, &[input.clone()], &mut output)?;392393assert_eq!(input, output[0]);394395// Sad path: unknown flags396397let err = Val::Flags(vec!["B".into(), "D".into(), "F".into()]);398let err = func.call(&mut store, &[err], &mut output).unwrap_err();399assert!(err.to_string().contains("unknown flag"), "{err}");400401Ok(())402}403404#[test]405fn everything() -> Result<()> {406// This serves to test both nested types and storing parameters on the heap (i.e. exceeding `MAX_STACK_PARAMS`)407408let engine = super::engine();409let mut store = Store::new(&engine, ());410411let component = Component::new(412&engine,413make_echo_component_with_params(414r#"415(type $b' (enum "a" "b"))416(export $b "b" (type $b'))417(type $c' (record (field "D" bool) (field "E" u32)))418(export $c "c" (type $c'))419(type $f' (flags "G" "H" "I"))420(export $f "f" (type $f'))421(type $m' (record (field "N" bool) (field "O" u32)))422(export $m "m" (type $m'))423(type $j' (variant424(case "K" u32)425(case "L" float64)426(case "M" $m)427))428(export $j "j" (type $j'))429430(type $Foo' (record431(field "A" u32)432(field "B" $b)433(field "C" $c)434(field "F" (list $f))435(field "J" $j)436(field "P" s8)437(field "Q" s16)438(field "R" s32)439(field "S" s64)440(field "T" float32)441(field "U" float64)442(field "V" string)443(field "W" char)444(field "Y" (tuple u32 u32))445(field "AA" (option u32))446(field "BB" (result string (error string)))447))448"#,449&[450Param(Type::I32, Some(0)),451Param(Type::U8, Some(4)),452Param(Type::U8, Some(5)),453Param(Type::I32, Some(8)),454Param(Type::I32, Some(12)),455Param(Type::I32, Some(16)),456Param(Type::U8, Some(20)),457Param(Type::I64, Some(28)),458Param(Type::I32, Some(32)),459Param(Type::S8, Some(36)),460Param(Type::S16, Some(38)),461Param(Type::I32, Some(40)),462Param(Type::I64, Some(48)),463Param(Type::F32, Some(56)),464Param(Type::F64, Some(64)),465Param(Type::I32, Some(72)),466Param(Type::I32, Some(76)),467Param(Type::I32, Some(80)),468Param(Type::I32, Some(84)),469Param(Type::I32, Some(88)),470Param(Type::I64, Some(96)),471Param(Type::U8, Some(104)),472Param(Type::I32, Some(108)),473Param(Type::U8, Some(112)),474Param(Type::I32, Some(116)),475Param(Type::I32, Some(120)),476],477),478)?;479let instance = Linker::new(&engine).instantiate(&mut store, &component)?;480let func = instance.get_func(&mut store, "echo").unwrap();481let input = Val::Record(vec![482("A".into(), Val::U32(32343)),483("B".into(), Val::Enum("b".to_string())),484(485"C".into(),486Val::Record(vec![487("D".to_string(), Val::Bool(false)),488("E".to_string(), Val::U32(2084037802)),489]),490),491(492"F".into(),493Val::List(vec![Val::Flags(vec!["G".to_string(), "I".to_string()])]),494),495(496"J".into(),497Val::Variant("L".to_string(), Some(Box::new(Val::Float64(3.14159265)))),498),499("P".into(), Val::S8(42)),500("Q".into(), Val::S16(4242)),501("R".into(), Val::S32(42424242)),502("S".into(), Val::S64(424242424242424242)),503("T".into(), Val::Float32(3.14159265)),504("U".into(), Val::Float64(3.14159265)),505("V".into(), Val::String("wow, nice types".to_string())),506("W".into(), Val::Char('��')),507("Y".into(), Val::Tuple(vec![Val::U32(42), Val::U32(24)])),508(509"AA".into(),510Val::Option(Some(Box::new(Val::U32(314159265)))),511),512(513"BB".into(),514Val::Result(Ok(Some(Box::new(Val::String("no problem".to_string()))))),515),516]);517let mut output = [Val::Bool(false)];518func.call(&mut store, &[input.clone()], &mut output)?;519520assert_eq!(input, output[0]);521522Ok(())523}524525#[test]526fn introspection() -> Result<()> {527let engine = super::engine();528529let component = Component::new(530&engine,531format!(532r#"533(component534(import "res" (type $res (sub resource)))535536(import "ai" (instance $i))537(import "bi" (instance $i2 (export "m" (core module))))538539(alias export $i2 "m" (core module $m))540541(type $t (func (param "a" u32) (result u32)))542(component $a543(core module $m544(func (export "add-five") (param i32) (result i32)545local.get 0546i32.const 5547i32.add)548)549(core instance $m (instantiate $m))550(func (export "add-five") (type $t) (canon lift (core func $m "add-five")))551)552(component $b553(import "interface-v1" (instance $i554(export "add-five" (func (type $t)))))555(core module $m556(func $add-five (import "interface-0.1.0" "add-five") (param i32) (result i32))557(func) ;; causes index out of bounds558(func (export "run") (result i32) i32.const 0 call $add-five)559)560(core func $add-five (canon lower (func $i "add-five")))561(core instance $i (instantiate 0562(with "interface-0.1.0" (instance563(export "add-five" (func $add-five))564))565))566(func (result u32) (canon lift (core func $i "run")))567(export "run" (func 1))568)569(instance $a (instantiate $a))570(instance $b (instantiate $b (with "interface-v1" (instance $a))))571(export "run" (func $b "run"))572573(component $c574(component $c575(export "m" (core module $m))576)577(instance $c (instantiate $c))578(export "i" (instance $c))579)580(instance $c (instantiate $c))581(export "i" (instance $c))582(export "r" (instance $i))583(export "r2" (instance $i2))584585(type $b' (enum "a" "b"))586(export $b "b" (type $b'))587(type $c' (record (field "D" bool) (field "E" u32)))588(export $c "c" (type $c'))589(type $f' (flags "G" "H" "I"))590(export $f "f" (type $f'))591(type $m' (record (field "N" bool) (field "O" u32)))592(export $m "m" (type $m'))593(type $j' (variant594(case "K" u32)595(case "L" float64)596(case "M" $m)597))598(export $j "j" (type $j'))599600(type $Foo' (record601(field "A" u32)602(field "B" $b)603(field "C" $c)604(field "F" (list $f))605(field "J" $j)606(field "P" s8)607(field "Q" s16)608(field "R" s32)609(field "S" s64)610(field "T" float32)611(field "U" float64)612(field "V" string)613(field "W" char)614(field "Y" (tuple u32 u32))615(field "AA" (option u32))616(field "BB" (result string (error string)))617(field "CC" (own $res))618))619(export $Foo "foo" (type $Foo'))620621(core module $m2622(func (export "f") (param i32) (result i32)623local.get 0624)625(memory (export "memory") 1)626{REALLOC_AND_FREE}627)628(core instance $i3 (instantiate $m2))629630(func (export "fn") (param "x" (option $Foo)) (result (option (tuple u32 u32)))631(canon lift632(core func $i3 "f")633(memory $i3 "memory")634(realloc (func $i3 "realloc"))635)636)637)638"#639),640)?;641642struct MyType;643644let mut linker = Linker::<()>::new(&engine);645linker646.root()647.resource("res", ResourceType::host::<MyType>(), |_, _| Ok(()))?;648linker.instance("ai")?;649linker650.instance("bi")?651.module("m", &Module::new(&engine, "(module)")?)?;652653let component_ty = linker.substituted_component_type(&component)?;654655let mut imports = component_ty.imports(linker.engine());656assert_eq!(imports.len(), 3);657let (name, res_ty) = imports.next().unwrap();658assert_eq!(name, "res");659let ComponentItem::Resource(res_ty) = res_ty else {660panic!("`res` import item of wrong type")661};662assert_eq!(res_ty, ResourceType::host::<MyType>());663664let (name, ai_ty) = imports.next().unwrap();665assert_eq!(name, "ai");666let ComponentItem::ComponentInstance(ai_ty) = ai_ty else {667panic!("`ai` import item of wrong type")668};669assert_eq!(ai_ty.exports(linker.engine()).len(), 0);670671let (name, bi_ty) = imports.next().unwrap();672assert_eq!(name, "bi");673let ComponentItem::ComponentInstance(bi_ty) = bi_ty else {674panic!("`bi` import item of wrong type")675};676let mut bi_exports = bi_ty.exports(linker.engine());677assert_eq!(bi_exports.len(), 1);678let (name, bi_m_ty) = bi_exports.next().unwrap();679assert_eq!(name, "m");680let ComponentItem::Module(bi_m_ty) = bi_m_ty else {681panic!("`bi.m` import item of wrong type")682};683assert_eq!(bi_m_ty.imports(linker.engine()).len(), 0);684assert_eq!(bi_m_ty.exports(linker.engine()).len(), 0);685686let mut exports = component_ty.exports(linker.engine());687assert_eq!(exports.len(), 11);688689let (name, run_ty) = exports.next().unwrap();690assert_eq!(name, "run");691let ComponentItem::ComponentFunc(run_ty) = run_ty else {692panic!("`run` export item of wrong type")693};694assert_eq!(run_ty.params().len(), 0);695696let mut run_results = run_ty.results();697assert_eq!(run_results.len(), 1);698assert_eq!(run_results.next().unwrap(), types::Type::U32);699700let (name, i_ty) = exports.next().unwrap();701assert_eq!(name, "i");702let ComponentItem::ComponentInstance(i_ty) = i_ty else {703panic!("`i` export item of wrong type")704};705let mut i_ty_exports = i_ty.exports(linker.engine());706assert_eq!(i_ty_exports.len(), 1);707let (name, i_i_ty) = i_ty_exports.next().unwrap();708assert_eq!(name, "i");709let ComponentItem::ComponentInstance(i_i_ty) = i_i_ty else {710panic!("`i.i` import item of wrong type")711};712let mut i_i_ty_exports = i_i_ty.exports(linker.engine());713assert_eq!(i_i_ty_exports.len(), 1);714let (name, i_i_m_ty) = i_i_ty_exports.next().unwrap();715assert_eq!(name, "m");716let ComponentItem::Module(i_i_m_ty) = i_i_m_ty else {717panic!("`i.i.m` import item of wrong type")718};719assert_eq!(i_i_m_ty.imports(linker.engine()).len(), 0);720assert_eq!(i_i_m_ty.exports(linker.engine()).len(), 0);721722let (name, r_ty) = exports.next().unwrap();723assert_eq!(name, "r");724let ComponentItem::ComponentInstance(r_ty) = r_ty else {725panic!("`r` export item of wrong type")726};727assert_eq!(r_ty.exports(linker.engine()).len(), 0);728729let (name, r2_ty) = exports.next().unwrap();730assert_eq!(name, "r2");731let ComponentItem::ComponentInstance(r2_ty) = r2_ty else {732panic!("`r2` export item of wrong type")733};734let mut r2_exports = r2_ty.exports(linker.engine());735assert_eq!(r2_exports.len(), 1);736let (name, r2_m_ty) = r2_exports.next().unwrap();737assert_eq!(name, "m");738let ComponentItem::Module(r2_m_ty) = r2_m_ty else {739panic!("`r2.m` export item of wrong type")740};741assert_eq!(r2_m_ty.imports(linker.engine()).len(), 0);742assert_eq!(r2_m_ty.exports(linker.engine()).len(), 0);743744let (name, b_ty) = exports.next().unwrap();745assert_eq!(name, "b");746let ComponentItem::Type(b_ty) = b_ty else {747panic!("`b` export item of wrong type")748};749assert_eq!(b_ty.unwrap_enum().names().collect::<Vec<_>>(), ["a", "b"]);750751let (name, c_ty) = exports.next().unwrap();752assert_eq!(name, "c");753let ComponentItem::Type(c_ty) = c_ty else {754panic!("`c` export item of wrong type")755};756let mut fields = c_ty.unwrap_record().fields();757{758let Field { name, ty } = fields.next().unwrap();759assert_eq!(name, "D");760assert_eq!(ty, types::Type::Bool);761let Field { name, ty } = fields.next().unwrap();762assert_eq!(name, "E");763assert_eq!(ty, types::Type::U32);764}765766let (name, f_ty) = exports.next().unwrap();767assert_eq!(name, "f");768let ComponentItem::Type(f_ty) = f_ty else {769panic!("`f` export item of wrong type")770};771assert_eq!(772f_ty.unwrap_flags().names().collect::<Vec<_>>(),773["G", "H", "I"]774);775776let (name, m_ty) = exports.next().unwrap();777assert_eq!(name, "m");778let ComponentItem::Type(m_ty) = m_ty else {779panic!("`m` export item of wrong type")780};781{782let mut fields = m_ty.unwrap_record().fields();783let Field { name, ty } = fields.next().unwrap();784assert_eq!(name, "N");785assert_eq!(ty, types::Type::Bool);786let Field { name, ty } = fields.next().unwrap();787assert_eq!(name, "O");788assert_eq!(ty, types::Type::U32);789}790791let (name, j_ty) = exports.next().unwrap();792assert_eq!(name, "j");793let ComponentItem::Type(j_ty) = j_ty else {794panic!("`j` export item of wrong type")795};796let mut cases = j_ty.unwrap_variant().cases();797{798let Case { name, ty } = cases.next().unwrap();799assert_eq!(name, "K");800assert_eq!(ty, Some(types::Type::U32));801let Case { name, ty } = cases.next().unwrap();802assert_eq!(name, "L");803assert_eq!(ty, Some(types::Type::Float64));804let Case { name, ty } = cases.next().unwrap();805assert_eq!(name, "M");806assert_eq!(ty, Some(m_ty));807}808809let (name, foo_ty) = exports.next().unwrap();810assert_eq!(name, "foo");811let ComponentItem::Type(foo_ty) = foo_ty else {812panic!("`foo` export item of wrong type")813};814{815let mut fields = foo_ty.unwrap_record().fields();816assert_eq!(fields.len(), 17);817let Field { name, ty } = fields.next().unwrap();818assert_eq!(name, "A");819assert_eq!(ty, types::Type::U32);820let Field { name, ty } = fields.next().unwrap();821assert_eq!(name, "B");822assert_eq!(ty, b_ty);823let Field { name, ty } = fields.next().unwrap();824assert_eq!(name, "C");825assert_eq!(ty, c_ty);826let Field { name, ty } = fields.next().unwrap();827assert_eq!(name, "F");828let ty = ty.unwrap_list();829assert_eq!(ty.ty(), f_ty);830let Field { name, ty } = fields.next().unwrap();831assert_eq!(name, "J");832assert_eq!(ty, j_ty);833let Field { name, ty } = fields.next().unwrap();834assert_eq!(name, "P");835assert_eq!(ty, types::Type::S8);836let Field { name, ty } = fields.next().unwrap();837assert_eq!(name, "Q");838assert_eq!(ty, types::Type::S16);839let Field { name, ty } = fields.next().unwrap();840assert_eq!(name, "R");841assert_eq!(ty, types::Type::S32);842let Field { name, ty } = fields.next().unwrap();843assert_eq!(name, "S");844assert_eq!(ty, types::Type::S64);845let Field { name, ty } = fields.next().unwrap();846assert_eq!(name, "T");847assert_eq!(ty, types::Type::Float32);848let Field { name, ty } = fields.next().unwrap();849assert_eq!(name, "U");850assert_eq!(ty, types::Type::Float64);851let Field { name, ty } = fields.next().unwrap();852assert_eq!(name, "V");853assert_eq!(ty, types::Type::String);854let Field { name, ty } = fields.next().unwrap();855assert_eq!(name, "W");856assert_eq!(ty, types::Type::Char);857let Field { name, ty } = fields.next().unwrap();858assert_eq!(name, "Y");859assert_eq!(860ty.unwrap_tuple().types().collect::<Vec<_>>(),861[types::Type::U32, types::Type::U32]862);863let Field { name, ty } = fields.next().unwrap();864assert_eq!(name, "AA");865assert_eq!(ty.unwrap_option().ty(), types::Type::U32);866let Field { name, ty } = fields.next().unwrap();867assert_eq!(name, "BB");868let ty = ty.unwrap_result();869assert_eq!(ty.ok(), Some(types::Type::String));870assert_eq!(ty.err(), Some(types::Type::String));871let Field { name, ty } = fields.next().unwrap();872assert_eq!(name, "CC");873assert_eq!(*ty.unwrap_own(), res_ty);874}875876let (name, fn_ty) = exports.next().unwrap();877assert_eq!(name, "fn");878let ComponentItem::ComponentFunc(fn_ty) = fn_ty else {879panic!("`fn` export item of wrong type")880};881let mut params = fn_ty.params();882assert_eq!(params.len(), 1);883let (name, param) = params.next().unwrap();884assert_eq!(name, "x");885assert_eq!(param.unwrap_option().ty(), foo_ty);886887let mut results = fn_ty.results();888assert_eq!(results.len(), 1);889assert_eq!(890results891.next()892.unwrap()893.unwrap_option()894.ty()895.unwrap_tuple()896.types()897.collect::<Vec<_>>(),898[types::Type::U32, types::Type::U32]899);900Ok(())901}902903904