Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/tests/all/component_model/macros.rs
1692 views
1
#![cfg(not(miri))]
2
3
use super::{TypedFuncExt, make_echo_component};
4
use anyhow::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]
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_and_post_return(&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_and_post_return(&mut store, (input,))?;
120
121
assert_eq!((input,), output);
122
123
Ok(())
124
}
125
126
#[test]
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_and_post_return(&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_and_post_return(&mut store, (input,))?;
244
245
assert_eq!((input,), output);
246
}
247
248
Ok(())
249
}
250
251
#[test]
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_and_post_return(&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_and_post_return(&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]
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_and_post_return(&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_and_post_return(&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_and_post_return(&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_and_post_return(&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_and_post_return(&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_and_post_return(&mut store, (input,))?;
688
689
assert_eq!((input,), output);
690
}
691
692
Ok(())
693
}
694
695