1 #![cfg(not(miri))]
2 
3 use super::make_echo_component;
4 use wasmtime::Result;
5 use wasmtime::component::{Component, ComponentType, Lift, Linker, Lower};
6 use wasmtime::{Engine, Store};
7 use wasmtime_test_macros::{add_variants, flags_test};
8 
9 #[test]
record_derive() -> Result<()>10 fn record_derive() -> Result<()> {
11     #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
12     #[component(record)]
13     struct Foo {
14         #[component(name = "foo-bar-baz")]
15         a: i32,
16         b: u32,
17     }
18 
19     let engine = super::engine();
20     let mut store = Store::new(&engine, ());
21 
22     // Happy path: component type matches field count, names, and types
23 
24     let component = Component::new(
25         &engine,
26         make_echo_component(r#"(record (field "foo-bar-baz" s32) (field "b" u32))"#, 8),
27     )?;
28     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
29 
30     let input = Foo { a: -42, b: 73 };
31     let output = instance
32         .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")?
33         .call(&mut store, (input,))?;
34 
35     assert_eq!((input,), output);
36 
37     // Sad path: field count mismatch (too few)
38 
39     let component = Component::new(
40         &engine,
41         make_echo_component(r#"(record (field "foo-bar-baz" s32))"#, 4),
42     )?;
43     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
44 
45     assert!(
46         instance
47             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
48             .is_err()
49     );
50 
51     // Sad path: field count mismatch (too many)
52 
53     let component = Component::new(
54         &engine,
55         make_echo_component(
56             r#"(record (field "foo-bar-baz" s32) (field "b" u32) (field "c" u32))"#,
57             12,
58         ),
59     )?;
60     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
61 
62     assert!(
63         instance
64             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
65             .is_err()
66     );
67 
68     // Sad path: field name mismatch
69 
70     let component = Component::new(
71         &engine,
72         make_echo_component(r#"(record (field "a" s32) (field "b" u32))"#, 8),
73     )?;
74     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
75 
76     assert!(
77         instance
78             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
79             .is_err()
80     );
81 
82     // Sad path: field type mismatch
83 
84     let component = Component::new(
85         &engine,
86         make_echo_component(r#"(record (field "foo-bar-baz" s32) (field "b" s32))"#, 8),
87     )?;
88     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
89 
90     assert!(
91         instance
92             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
93             .is_err()
94     );
95 
96     // Happy path redux, with generics this time
97 
98     #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
99     #[component(record)]
100     struct Generic<A, B> {
101         #[component(name = "foo-bar-baz")]
102         a: A,
103         b: B,
104     }
105 
106     let input = Generic {
107         a: -43_i32,
108         b: 74_u32,
109     };
110 
111     let component = Component::new(
112         &engine,
113         make_echo_component(r#"(record (field "foo-bar-baz" s32) (field "b" u32))"#, 8),
114     )?;
115     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
116 
117     let output = instance
118         .get_typed_func::<(Generic<i32, u32>,), (Generic<i32, u32>,)>(&mut store, "echo")?
119         .call(&mut store, (input,))?;
120 
121     assert_eq!((input,), output);
122 
123     Ok(())
124 }
125 
126 #[test]
variant_derive() -> Result<()>127 fn variant_derive() -> Result<()> {
128     #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
129     #[component(variant)]
130     enum Foo {
131         #[component(name = "foo-bar-baz")]
132         A(i32),
133         B(u32),
134         C,
135     }
136 
137     let engine = super::engine();
138     let mut store = Store::new(&engine, ());
139 
140     // Happy path: component type matches case count, names, and types
141 
142     let component = Component::new(
143         &engine,
144         make_echo_component(
145             r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C"))"#,
146             8,
147         ),
148     )?;
149     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
150     let func = instance.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")?;
151 
152     for &input in &[Foo::A(-42), Foo::B(73), Foo::C] {
153         let output = func.call(&mut store, (input,))?;
154 
155         assert_eq!((input,), output);
156     }
157 
158     // Sad path: case count mismatch (too few)
159 
160     let component = Component::new(
161         &engine,
162         make_echo_component(r#"(variant (case "foo-bar-baz" s32) (case "B" u32))"#, 8),
163     )?;
164     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
165 
166     assert!(
167         instance
168             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
169             .is_err()
170     );
171 
172     // Sad path: case count mismatch (too many)
173 
174     let component = Component::new(
175         &engine,
176         make_echo_component(
177             r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C") (case "D" u32))"#,
178             8,
179         ),
180     )?;
181     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
182 
183     assert!(
184         instance
185             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
186             .is_err()
187     );
188 
189     // Sad path: case name mismatch
190 
191     let component = Component::new(
192         &engine,
193         make_echo_component(r#"(variant (case "A" s32) (case "B" u32) (case "C"))"#, 8),
194     )?;
195     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
196 
197     assert!(
198         instance
199             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
200             .is_err()
201     );
202 
203     // Sad path: case type mismatch
204 
205     let component = Component::new(
206         &engine,
207         make_echo_component(
208             r#"(variant (case "foo-bar-baz" s32) (case "B" s32) (case "C"))"#,
209             8,
210         ),
211     )?;
212     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
213 
214     assert!(
215         instance
216             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
217             .is_err()
218     );
219 
220     // Happy path redux, with generics this time
221 
222     #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
223     #[component(variant)]
224     enum Generic<A, B> {
225         #[component(name = "foo-bar-baz")]
226         A(A),
227         B(B),
228         C,
229     }
230 
231     let component = Component::new(
232         &engine,
233         make_echo_component(
234             r#"(variant (case "foo-bar-baz" s32) (case "B" u32) (case "C"))"#,
235             8,
236         ),
237     )?;
238     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
239     let func = instance
240         .get_typed_func::<(Generic<i32, u32>,), (Generic<i32, u32>,)>(&mut store, "echo")?;
241 
242     for &input in &[Generic::<i32, u32>::A(-42), Generic::B(73), Generic::C] {
243         let output = func.call(&mut store, (input,))?;
244 
245         assert_eq!((input,), output);
246     }
247 
248     Ok(())
249 }
250 
251 #[test]
enum_derive() -> Result<()>252 fn enum_derive() -> Result<()> {
253     #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
254     #[component(enum)]
255     #[repr(u8)]
256     enum Foo {
257         #[component(name = "foo-bar-baz")]
258         A,
259         B,
260         C,
261     }
262 
263     let engine = super::engine();
264     let mut store = Store::new(&engine, ());
265 
266     // Happy path: component type matches case count and names
267 
268     let component = Component::new(
269         &engine,
270         make_echo_component(r#"(enum "foo-bar-baz" "B" "C")"#, 4),
271     )?;
272     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
273     let func = instance.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")?;
274 
275     for &input in &[Foo::A, Foo::B, Foo::C] {
276         let output = func.call(&mut store, (input,))?;
277 
278         assert_eq!((input,), output);
279     }
280 
281     // Sad path: case count mismatch (too few)
282 
283     let component = Component::new(
284         &engine,
285         make_echo_component(r#"(enum "foo-bar-baz" "B")"#, 4),
286     )?;
287     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
288 
289     assert!(
290         instance
291             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
292             .is_err()
293     );
294 
295     // Sad path: case count mismatch (too many)
296 
297     let component = Component::new(
298         &engine,
299         make_echo_component(r#"(enum "foo-bar-baz" "B" "C" "D")"#, 4),
300     )?;
301     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
302 
303     assert!(
304         instance
305             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
306             .is_err()
307     );
308 
309     // Sad path: case name mismatch
310 
311     let component = Component::new(&engine, make_echo_component(r#"(enum "A" "B" "C")"#, 4))?;
312     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
313 
314     assert!(
315         instance
316             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
317             .is_err()
318     );
319 
320     // Happy path redux, with large enums (i.e. more than 2^8 cases)
321 
322     #[add_variants(257)]
323     #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
324     #[component(enum)]
325     #[repr(u16)]
326     enum Many {}
327 
328     let component = Component::new(
329         &engine,
330         make_echo_component(
331             &format!(
332                 "(enum {})",
333                 (0..257)
334                     .map(|index| format!(r#""V{index}""#))
335                     .collect::<Vec<_>>()
336                     .join(" ")
337             ),
338             4,
339         ),
340     )?;
341     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
342     let func = instance.get_typed_func::<(Many,), (Many,)>(&mut store, "echo")?;
343 
344     for &input in &[Many::V0, Many::V1, Many::V254, Many::V255, Many::V256] {
345         let output = func.call(&mut store, (input,))?;
346 
347         assert_eq!((input,), output);
348     }
349 
350     // TODO: The following case takes forever (i.e. I gave up after 30 minutes) to compile; we'll need to profile
351     // the compiler to find out why, which may point the way to a more efficient option.  On the other hand, this
352     // may not be worth spending time on.  Enums with over 2^16 variants are rare enough.
353 
354     // #[add_variants(65537)]
355     // #[derive(ComponentType, Lift, Lower, PartialEq, Eq, Debug, Copy, Clone)]
356     // #[component(enum)]
357     // #[repr(u32)]
358     // enum ManyMore {}
359 
360     Ok(())
361 }
362 
363 #[test]
flags() -> Result<()>364 fn flags() -> Result<()> {
365     let config = wasmtime_test_util::component::config();
366     let engine = Engine::new(&config)?;
367     let mut store = Store::new(&engine, ());
368 
369     // Simple 8-bit flags
370     wasmtime::component::flags! {
371         Foo {
372             #[component(name = "foo-bar-baz")]
373             const A;
374             const B;
375             const C;
376         }
377     }
378 
379     assert_eq!(Foo::default(), (Foo::A | Foo::B) & Foo::C);
380     assert_eq!(Foo::B, (Foo::A | Foo::B) & Foo::B);
381     assert_eq!(Foo::A, (Foo::A | Foo::B) & Foo::A);
382     assert_eq!(Foo::A | Foo::B, Foo::A ^ Foo::B);
383     assert_eq!(Foo::default(), Foo::A ^ Foo::A);
384     assert_eq!(Foo::B | Foo::C, !Foo::A);
385 
386     // Happy path: component type matches flag count and names
387 
388     let component = Component::new(
389         &engine,
390         make_echo_component(r#"(flags "foo-bar-baz" "B" "C")"#, 4),
391     )?;
392     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
393     let func = instance.get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")?;
394 
395     for n in 0..8 {
396         let mut input = Foo::default();
397         if (n & 1) != 0 {
398             input |= Foo::A;
399         }
400         if (n & 2) != 0 {
401             input |= Foo::B;
402         }
403         if (n & 4) != 0 {
404             input |= Foo::C;
405         }
406 
407         let output = func.call(&mut store, (input,))?;
408 
409         assert_eq!((input,), output);
410     }
411 
412     // Sad path: flag count mismatch (too few)
413 
414     let component = Component::new(
415         &engine,
416         make_echo_component(r#"(flags "foo-bar-baz" "B")"#, 4),
417     )?;
418     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
419 
420     assert!(
421         instance
422             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
423             .is_err()
424     );
425 
426     // Sad path: flag count mismatch (too many)
427 
428     let component = Component::new(
429         &engine,
430         make_echo_component(r#"(flags "foo-bar-baz" "B" "C" "D")"#, 4),
431     )?;
432     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
433 
434     assert!(
435         instance
436             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
437             .is_err()
438     );
439 
440     // Sad path: flag name mismatch
441 
442     let component = Component::new(&engine, make_echo_component(r#"(flags "A" "B" "C")"#, 4))?;
443     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
444 
445     assert!(
446         instance
447             .get_typed_func::<(Foo,), (Foo,)>(&mut store, "echo")
448             .is_err()
449     );
450 
451     // Happy path redux, with large flag count (exactly 8)
452 
453     flags_test!(Foo8Exact, 8);
454 
455     assert_eq!(
456         Foo8Exact::default(),
457         (Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F7
458     );
459     assert_eq!(
460         Foo8Exact::F6,
461         (Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F6
462     );
463     assert_eq!(
464         Foo8Exact::F0,
465         (Foo8Exact::F0 | Foo8Exact::F6) & Foo8Exact::F0
466     );
467     assert_eq!(Foo8Exact::F0 | Foo8Exact::F6, Foo8Exact::F0 ^ Foo8Exact::F6);
468     assert_eq!(Foo8Exact::default(), Foo8Exact::F0 ^ Foo8Exact::F0);
469     assert_eq!(
470         Foo8Exact::F1
471             | Foo8Exact::F2
472             | Foo8Exact::F3
473             | Foo8Exact::F4
474             | Foo8Exact::F5
475             | Foo8Exact::F6
476             | Foo8Exact::F7,
477         !Foo8Exact::F0
478     );
479 
480     let component = Component::new(
481         &engine,
482         make_echo_component(
483             &format!(
484                 r#"(flags {})"#,
485                 (0..8)
486                     .map(|index| format!(r#""F{index}""#))
487                     .collect::<Vec<_>>()
488                     .join(" ")
489             ),
490             4,
491         ),
492     )?;
493     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
494     let func = instance.get_typed_func::<(Foo8Exact,), (Foo8Exact,)>(&mut store, "echo")?;
495 
496     for &input in &[
497         Foo8Exact::F0,
498         Foo8Exact::F1,
499         Foo8Exact::F5,
500         Foo8Exact::F6,
501         Foo8Exact::F7,
502     ] {
503         let output = func.call(&mut store, (input,))?;
504 
505         assert_eq!((input,), output);
506     }
507 
508     // Happy path redux, with large flag count (more than 8)
509 
510     flags_test!(Foo16, 9);
511 
512     assert_eq!(Foo16::default(), (Foo16::F0 | Foo16::F7) & Foo16::F8);
513     assert_eq!(Foo16::F7, (Foo16::F0 | Foo16::F7) & Foo16::F7);
514     assert_eq!(Foo16::F0, (Foo16::F0 | Foo16::F7) & Foo16::F0);
515     assert_eq!(Foo16::F0 | Foo16::F7, Foo16::F0 ^ Foo16::F7);
516     assert_eq!(Foo16::default(), Foo16::F0 ^ Foo16::F0);
517     assert_eq!(
518         Foo16::F1
519             | Foo16::F2
520             | Foo16::F3
521             | Foo16::F4
522             | Foo16::F5
523             | Foo16::F6
524             | Foo16::F7
525             | Foo16::F8,
526         !Foo16::F0
527     );
528 
529     let component = Component::new(
530         &engine,
531         make_echo_component(
532             &format!(
533                 "(flags {})",
534                 (0..9)
535                     .map(|index| format!(r#""F{index}""#))
536                     .collect::<Vec<_>>()
537                     .join(" ")
538             ),
539             4,
540         ),
541     )?;
542     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
543     let func = instance.get_typed_func::<(Foo16,), (Foo16,)>(&mut store, "echo")?;
544 
545     for &input in &[Foo16::F0, Foo16::F1, Foo16::F6, Foo16::F7, Foo16::F8] {
546         let output = func.call(&mut store, (input,))?;
547 
548         assert_eq!((input,), output);
549     }
550 
551     // Happy path redux, with large flag count (exactly 16)
552 
553     flags_test!(Foo16Exact, 16);
554 
555     assert_eq!(
556         Foo16Exact::default(),
557         (Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F5
558     );
559     assert_eq!(
560         Foo16Exact::F14,
561         (Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F14
562     );
563     assert_eq!(
564         Foo16Exact::F0,
565         (Foo16Exact::F0 | Foo16Exact::F14) & Foo16Exact::F0
566     );
567     assert_eq!(
568         Foo16Exact::F0 | Foo16Exact::F14,
569         Foo16Exact::F0 ^ Foo16Exact::F14
570     );
571     assert_eq!(Foo16Exact::default(), Foo16Exact::F0 ^ Foo16Exact::F0);
572     assert_eq!(
573         Foo16Exact::F0 | Foo16Exact::F15,
574         !((!Foo16Exact::F0) & (!Foo16Exact::F15))
575     );
576 
577     let component = Component::new(
578         &engine,
579         make_echo_component(
580             &format!(
581                 r#"(flags {})"#,
582                 (0..16)
583                     .map(|index| format!(r#""F{index}""#))
584                     .collect::<Vec<_>>()
585                     .join(" ")
586             ),
587             4,
588         ),
589     )?;
590     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
591     let func = instance.get_typed_func::<(Foo16Exact,), (Foo16Exact,)>(&mut store, "echo")?;
592 
593     for &input in &[
594         Foo16Exact::F0,
595         Foo16Exact::F1,
596         Foo16Exact::F13,
597         Foo16Exact::F14,
598         Foo16Exact::F15,
599     ] {
600         let output = func.call(&mut store, (input,))?;
601 
602         assert_eq!((input,), output);
603     }
604 
605     // Happy path redux, with large flag count (more than 16)
606 
607     flags_test!(Foo32, 17);
608 
609     assert_eq!(Foo32::default(), (Foo32::F0 | Foo32::F15) & Foo32::F16);
610     assert_eq!(Foo32::F15, (Foo32::F0 | Foo32::F15) & Foo32::F15);
611     assert_eq!(Foo32::F0, (Foo32::F0 | Foo32::F15) & Foo32::F0);
612     assert_eq!(Foo32::F0 | Foo32::F15, Foo32::F0 ^ Foo32::F15);
613     assert_eq!(Foo32::default(), Foo32::F0 ^ Foo32::F0);
614     assert_eq!(Foo32::F0 | Foo32::F16, !((!Foo32::F0) & (!Foo32::F16)));
615 
616     let component = Component::new(
617         &engine,
618         make_echo_component(
619             &format!(
620                 "(flags {})",
621                 (0..17)
622                     .map(|index| format!(r#""F{index}""#))
623                     .collect::<Vec<_>>()
624                     .join(" ")
625             ),
626             4,
627         ),
628     )?;
629     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
630     let func = instance.get_typed_func::<(Foo32,), (Foo32,)>(&mut store, "echo")?;
631 
632     for &input in &[Foo32::F0, Foo32::F1, Foo32::F14, Foo32::F15, Foo32::F16] {
633         let output = func.call(&mut store, (input,))?;
634 
635         assert_eq!((input,), output);
636     }
637 
638     // Happy path redux, with large flag count (exactly 32)
639 
640     flags_test!(Foo32Exact, 32);
641 
642     assert_eq!(
643         Foo32Exact::default(),
644         (Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F31
645     );
646     assert_eq!(
647         Foo32Exact::F30,
648         (Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F30
649     );
650     assert_eq!(
651         Foo32Exact::F0,
652         (Foo32Exact::F0 | Foo32Exact::F30) & Foo32Exact::F0
653     );
654     assert_eq!(
655         Foo32Exact::F0 | Foo32Exact::F30,
656         Foo32Exact::F0 ^ Foo32Exact::F30
657     );
658     assert_eq!(Foo32Exact::default(), Foo32Exact::F0 ^ Foo32Exact::F0);
659     assert_eq!(
660         Foo32Exact::F0 | Foo32Exact::F15,
661         !((!Foo32Exact::F0) & (!Foo32Exact::F15))
662     );
663 
664     let component = Component::new(
665         &engine,
666         make_echo_component(
667             &format!(
668                 r#"(flags {})"#,
669                 (0..32)
670                     .map(|index| format!(r#""F{index}""#))
671                     .collect::<Vec<_>>()
672                     .join(" ")
673             ),
674             4,
675         ),
676     )?;
677     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
678     let func = instance.get_typed_func::<(Foo32Exact,), (Foo32Exact,)>(&mut store, "echo")?;
679 
680     for &input in &[
681         Foo32Exact::F0,
682         Foo32Exact::F1,
683         Foo32Exact::F29,
684         Foo32Exact::F30,
685         Foo32Exact::F31,
686     ] {
687         let output = func.call(&mut store, (input,))?;
688 
689         assert_eq!((input,), output);
690     }
691 
692     Ok(())
693 }
694