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