1 #![allow(dead_code)]
2 
3 macro_rules! gentest {
4     ($id:ident $name:tt $path:tt) => {
5         mod $id {
6             mod sugar {
7                 wasmtime::component::bindgen!(in $path);
8             }
9             mod async_ {
10                 wasmtime::component::bindgen!({
11                     path: $path,
12                     async: true,
13                 });
14             }
15             mod tracing {
16                 wasmtime::component::bindgen!({
17                     path: $path,
18                     tracing: true,
19                     verbose_tracing: true,
20                     ownership: Borrowing {
21                         duplicate_if_necessary: true
22                     }
23                 });
24             }
25         }
26     };
27 }
28 
29 component_macro_test_helpers::foreach!(gentest);
30 
31 mod with_key_and_resources {
32     use anyhow::Result;
33     use wasmtime::component::Resource;
34 
35     wasmtime::component::bindgen!({
36         inline: "
37             package demo:pkg;
38 
39             interface bar {
40                 resource a;
41                 resource b;
42             }
43 
44             world foo {
45                 resource a;
46                 resource b;
47 
48                 import foo: interface {
49                     resource a;
50                     resource b;
51                 }
52 
53                 import bar;
54             }
55         ",
56         with: {
57             "a": MyA,
58             "b": MyA,
59             "foo/a": MyA,
60             "foo/b": MyA,
61             "demo:pkg/bar/a": MyA,
62             "demo:pkg/bar/b": MyA,
63         },
64     });
65 
66     pub struct MyA;
67 
68     struct MyComponent;
69 
70     impl FooImports for MyComponent {}
71 
72     impl HostA for MyComponent {
73         fn drop(&mut self, _: Resource<MyA>) -> Result<()> {
74             loop {}
75         }
76     }
77 
78     impl HostB for MyComponent {
79         fn drop(&mut self, _: Resource<MyA>) -> Result<()> {
80             loop {}
81         }
82     }
83 
84     impl foo::Host for MyComponent {}
85 
86     impl foo::HostA for MyComponent {
87         fn drop(&mut self, _: Resource<MyA>) -> Result<()> {
88             loop {}
89         }
90     }
91 
92     impl foo::HostB for MyComponent {
93         fn drop(&mut self, _: Resource<MyA>) -> Result<()> {
94             loop {}
95         }
96     }
97 
98     impl demo::pkg::bar::Host for MyComponent {}
99 
100     impl demo::pkg::bar::HostA for MyComponent {
101         fn drop(&mut self, _: Resource<MyA>) -> Result<()> {
102             loop {}
103         }
104     }
105 
106     impl demo::pkg::bar::HostB for MyComponent {
107         fn drop(&mut self, _: Resource<MyA>) -> Result<()> {
108             loop {}
109         }
110     }
111 }
112 
113 mod trappable_errors_with_versioned_and_unversioned_packages {
114     wasmtime::component::bindgen!({
115         world: "foo:foo/nope",
116         inline: "
117             package foo:[email protected];
118 
119             interface a {
120                 variant error {
121                     other(string),
122                 }
123 
124                 f: func() -> result<_, error>;
125             }
126 
127             world foo {
128                 import a;
129             }
130         ",
131         path: "tests/codegen/unversioned-foo.wit",
132         trappable_error_type: {
133             "foo:foo/[email protected]/error" => MyX,
134         },
135     });
136 
137     #[allow(dead_code)]
138     type MyX = u64;
139 }
140 
141 mod trappable_errors {
142     wasmtime::component::bindgen!({
143         inline: "
144             package demo:pkg;
145 
146             interface a {
147                 type b = u64;
148 
149                 z1: func() -> result<_, b>;
150                 z2: func() -> result<_, b>;
151             }
152 
153             interface b {
154                 use a.{b};
155                 z: func() -> result<_, b>;
156             }
157 
158             interface c {
159                 type b = u64;
160             }
161 
162             interface d {
163                 use c.{b};
164                 z: func() -> result<_, b>;
165             }
166 
167             world foo {
168                 import a;
169                 import b;
170                 import d;
171             }
172         ",
173         trappable_error_type: {
174             "demo:pkg/a/b" => MyX,
175             "demo:pkg/c/b" => MyX,
176         },
177     });
178 
179     #[allow(dead_code)]
180     type MyX = u32;
181 }
182 
183 mod interface_name_with_rust_keyword {
184     wasmtime::component::bindgen!({
185         inline: "
186             package foo:foo;
187 
188             interface crate { }
189 
190             world foo {
191                 export crate;
192             }
193         "
194     });
195 }
196 
197 mod with_works_with_hierarchy {
198     mod bindings {
199         wasmtime::component::bindgen!({
200             inline: "
201                 package foo:foo;
202 
203                 interface a {
204                     record t {
205                         x: u32,
206                     }
207                     x: func() -> t;
208                 }
209 
210                 interface b {
211                     use a.{t};
212                     x: func() -> t;
213                 }
214 
215                 interface c {
216                     use b.{t};
217                     x: func() -> t;
218                 }
219 
220                 world foo {
221                     import c;
222                 }
223             "
224         });
225     }
226 
227     mod with_just_one_interface {
228         wasmtime::component::bindgen!({
229             inline: "
230                 package foo:foo;
231 
232                 interface a {
233                     record t {
234                         x: u32,
235                     }
236                     x: func() -> t;
237                 }
238 
239                 interface b {
240                     use a.{t};
241                     x: func() -> t;
242                 }
243 
244                 interface c {
245                     use b.{t};
246                     x: func() -> t;
247                 }
248 
249                 world foo {
250                     use c.{t};
251 
252                     import x: func() -> t;
253                 }
254             ",
255             with: { "foo:foo/a": super::bindings::foo::foo::a }
256         });
257 
258         struct X;
259 
260         impl FooImports for X {
261             fn x(&mut self) -> super::bindings::foo::foo::a::T {
262                 loop {}
263             }
264         }
265     }
266 
267     mod with_whole_package {
268         wasmtime::component::bindgen!({
269             inline: "
270                 package foo:foo;
271 
272                 interface a {
273                     record t {
274                         x: u32,
275                     }
276                     x: func() -> t;
277                 }
278 
279                 interface b {
280                     use a.{t};
281                     x: func() -> t;
282                 }
283 
284                 interface c {
285                     use b.{t};
286                     x: func() -> t;
287                 }
288 
289                 world foo {
290                     use c.{t};
291 
292                     import x: func() -> t;
293                 }
294             ",
295             with: { "foo:foo": super::bindings::foo::foo }
296         });
297 
298         struct X;
299 
300         impl FooImports for X {
301             fn x(&mut self) -> super::bindings::foo::foo::a::T {
302                 loop {}
303             }
304         }
305     }
306 
307     mod with_whole_namespace {
308         wasmtime::component::bindgen!({
309             inline: "
310                 package foo:foo;
311 
312                 interface a {
313                     record t {
314                         x: u32,
315                     }
316                     x: func() -> t;
317                 }
318 
319                 interface b {
320                     use a.{t};
321                     x: func() -> t;
322                 }
323 
324                 interface c {
325                     use b.{t};
326                     x: func() -> t;
327                 }
328 
329                 world foo {
330                     use c.{t};
331 
332                     import x: func() -> t;
333                 }
334             ",
335             with: { "foo": super::bindings::foo }
336         });
337 
338         struct X;
339 
340         impl FooImports for X {
341             fn x(&mut self) -> super::bindings::foo::foo::a::T {
342                 loop {}
343             }
344         }
345     }
346 }
347 
348 mod trappable_imports {
349     mod none {
350         wasmtime::component::bindgen!({
351             inline: "
352                 package foo:foo;
353 
354                 world foo {
355                     import foo: func();
356                 }
357             ",
358             trappable_imports: false,
359         });
360         struct X;
361 
362         impl FooImports for X {
363             fn foo(&mut self) {}
364         }
365     }
366 
367     mod all {
368         wasmtime::component::bindgen!({
369             inline: "
370                 package foo:foo;
371 
372                 world foo {
373                     import foo: func();
374                 }
375             ",
376             trappable_imports: true,
377         });
378         struct X;
379 
380         impl FooImports for X {
381             fn foo(&mut self) -> wasmtime::Result<()> {
382                 Ok(())
383             }
384         }
385     }
386 
387     mod some {
388         wasmtime::component::bindgen!({
389             inline: "
390                 package foo:foo;
391 
392                 world foo {
393                     import foo: func();
394                     import bar: func();
395                 }
396             ",
397             trappable_imports: ["foo"],
398         });
399         struct X;
400 
401         impl FooImports for X {
402             fn foo(&mut self) -> wasmtime::Result<()> {
403                 Ok(())
404             }
405             fn bar(&mut self) {}
406         }
407     }
408 
409     mod across_interfaces {
410         use wasmtime::component::Resource;
411 
412         wasmtime::component::bindgen!({
413             inline: "
414                 package foo:foo;
415 
416                 interface a {
417                     foo: func();
418                     bar: func();
419 
420                     resource r {
421                         constructor();
422                         foo: func();
423                         bar: static func();
424                     }
425                 }
426 
427                 world foo {
428                     import a;
429                     import foo: func();
430                     import bar: func();
431                     import i: interface {
432                         foo: func();
433                         bar: func();
434                     }
435 
436                 }
437             ",
438             trappable_imports: ["foo"],
439             with: { "foo:foo/a/r": R },
440         });
441 
442         struct X;
443         pub struct R;
444 
445         impl FooImports for X {
446             fn foo(&mut self) -> wasmtime::Result<()> {
447                 Ok(())
448             }
449             fn bar(&mut self) {}
450         }
451 
452         impl i::Host for X {
453             fn foo(&mut self) -> wasmtime::Result<()> {
454                 Ok(())
455             }
456             fn bar(&mut self) {}
457         }
458 
459         impl foo::foo::a::Host for X {
460             fn foo(&mut self) -> wasmtime::Result<()> {
461                 Ok(())
462             }
463             fn bar(&mut self) {}
464         }
465 
466         impl foo::foo::a::HostR for X {
467             fn new(&mut self) -> Resource<R> {
468                 loop {}
469             }
470             fn foo(&mut self, _: Resource<R>) {}
471             fn bar(&mut self) {}
472             fn drop(&mut self, _: Resource<R>) -> wasmtime::Result<()> {
473                 Ok(())
474             }
475         }
476     }
477 
478     mod resources {
479         use wasmtime::component::Resource;
480 
481         wasmtime::component::bindgen!({
482             inline: "
483                 package foo:foo;
484 
485                 interface a {
486                     resource r {
487                         constructor();
488                         foo: func();
489                         bar: static func();
490                     }
491                 }
492 
493                 world foo {
494                     import a;
495 
496                 }
497             ",
498             trappable_imports: [
499                 "[constructor]r",
500                 "[method]r.foo",
501                 "[static]r.bar",
502             ],
503             with: { "foo:foo/a/r": R },
504         });
505 
506         struct X;
507         pub struct R;
508 
509         impl foo::foo::a::Host for X {}
510 
511         impl foo::foo::a::HostR for X {
512             fn new(&mut self) -> wasmtime::Result<Resource<R>> {
513                 loop {}
514             }
515             fn foo(&mut self, _: Resource<R>) -> wasmtime::Result<()> {
516                 Ok(())
517             }
518             fn bar(&mut self) -> wasmtime::Result<()> {
519                 Ok(())
520             }
521             fn drop(&mut self, _: Resource<R>) -> wasmtime::Result<()> {
522                 Ok(())
523             }
524         }
525     }
526 }
527 
528 mod custom_derives {
529     use std::collections::{hash_map::RandomState, HashSet};
530 
531     wasmtime::component::bindgen!({
532         inline: "
533             package my:inline;
534 
535             interface blah {
536                 variant abc {
537                     a,
538                     b,
539                     c
540                 }
541 
542                 record foo {
543                     field1: string,
544                     field2: list<u32>,
545                     field3: abc
546                 }
547 
548                 bar: func(cool: foo);
549             }
550 
551             world baz {
552                 import blah;
553             }
554         ",
555         // Clone is included by default almost everywhere, so include it here to make sure it
556         // doesn't conflict
557         additional_derives: [serde::Serialize, serde::Deserialize, Hash, Clone, PartialEq, Eq],
558     });
559 
560     use my::inline::blah::{Abc, Foo, Host};
561 
562     struct X;
563 
564     impl Host for X {
565         fn bar(&mut self, cool: Foo) {
566             // Check that built in derives that I've added actually work by seeing that this hashes
567             let _blah: HashSet<Foo, RandomState> = HashSet::from_iter([Foo {
568                 field1: "hello".to_string(),
569                 field2: vec![1, 2, 3],
570                 field3: Abc::B,
571             }]);
572 
573             // Check that the attributes from an external crate actually work. If they don't work,
574             // compilation will fail here
575             let _ = serde_json::to_string(&cool);
576         }
577     }
578 }
579 
580 mod with_and_mixing_async {
581     mod with_async {
582         wasmtime::component::bindgen!({
583             inline: "
584                 package my:inline;
585                 interface foo {
586                     type t = u32;
587                     foo: func() -> t;
588                 }
589                 interface bar {
590                     use foo.{t};
591                     bar: func() -> t;
592                 }
593                 world x {
594                     import bar;
595                 }
596             ",
597             async: {
598                 only_imports: ["bar"],
599             },
600         });
601     }
602 
603     mod without_async {
604         wasmtime::component::bindgen!({
605             inline: "
606                 package my:inline;
607                 interface foo {
608                     type t = u32;
609                     foo: func() -> t;
610                 }
611                 interface bar {
612                     use foo.{t};
613                     bar: func() -> t;
614                 }
615                 world x {
616                     import bar;
617                 }
618             ",
619             with: {
620                 "my:inline/foo": super::with_async::my::inline::foo,
621             },
622             require_store_data_send: true,
623         });
624     }
625 
626     mod third {
627         wasmtime::component::bindgen!({
628             inline: "
629                 package my:inline;
630                 interface foo {
631                     type t = u32;
632                     foo: func() -> t;
633                 }
634                 interface bar {
635                     use foo.{t};
636                     bar: func() -> t;
637                 }
638                 interface baz {
639                     use bar.{t};
640                     baz: func() -> t;
641                 }
642                 world x {
643                     import baz;
644                 }
645             ",
646             with: {
647                 "my:inline/foo": super::with_async::my::inline::foo,
648                 "my:inline/bar": super::without_async::my::inline::bar,
649             },
650             require_store_data_send: true,
651         });
652     }
653 }
654 
655 mod trappable_error_type_and_versions {
656     struct MyError;
657 
658     mod package_no_version_path_no_version {
659         wasmtime::component::bindgen!({
660             inline: "
661                 package my:inline;
662                 interface i {
663                     enum e { a, b, c }
664                 }
665                 world foo {}
666             ",
667             trappable_error_type: {
668                 "my:inline/i/e" => super::MyError,
669             },
670         });
671     }
672     mod package_version_path_no_version {
673         wasmtime::component::bindgen!({
674             inline: "
675                 package my:[email protected];
676                 interface i {
677                     enum e { a, b, c }
678                 }
679                 world foo {}
680             ",
681             trappable_error_type: {
682                 "my:inline/i/e" => super::MyError,
683             },
684         });
685     }
686     mod package_version_path_version {
687         wasmtime::component::bindgen!({
688             inline: "
689                 package my:[email protected];
690                 interface i {
691                     enum e { a, b, c }
692                 }
693                 world foo {}
694             ",
695             trappable_error_type: {
696                 "my:inline/[email protected]/e" => super::MyError,
697             },
698         });
699     }
700 }
701 
702 mod paths {
703     mod multiple_paths {
704         wasmtime::component::bindgen!({
705             world: "test:paths/test",
706             inline: r#"
707             package test:paths;
708             world test {
709                 import paths:path1/test;
710                 export paths:path2/test;
711             }
712             "#,
713             path: ["tests/codegen/path1", "tests/codegen/path2"],
714         });
715     }
716 }
717