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