1 #![cfg(not(miri))]
2 #![allow(dead_code)]
3 
4 use super::engine;
5 use anyhow::Result;
6 use wasmtime::{
7     component::{Component, Linker},
8     Store,
9 };
10 
11 mod ownership;
12 mod results;
13 
14 mod no_imports {
15     use super::*;
16 
17     wasmtime::component::bindgen!({
18         inline: "
19             package foo:foo;
20 
21             world no-imports {
22                 export foo: interface {
23                     foo: func();
24                 }
25 
26                 export bar: func();
27             }
28         ",
29     });
30 
31     #[test]
32     fn run() -> Result<()> {
33         let engine = engine();
34 
35         let component = Component::new(
36             &engine,
37             r#"
38                 (component
39                     (core module $m
40                         (func (export ""))
41                     )
42                     (core instance $i (instantiate $m))
43 
44                     (func $f (export "bar") (canon lift (core func $i "")))
45 
46                     (instance $i (export "foo" (func $f)))
47                     (export "foo" (instance $i))
48                 )
49             "#,
50         )?;
51 
52         let linker = Linker::new(&engine);
53         let mut store = Store::new(&engine, ());
54         let no_imports = NoImports::instantiate(&mut store, &component, &linker)?;
55         no_imports.call_bar(&mut store)?;
56         no_imports.foo().call_foo(&mut store)?;
57         Ok(())
58     }
59 }
60 
61 mod one_import {
62     use super::*;
63 
64     wasmtime::component::bindgen!({
65         inline: "
66             package foo:foo;
67 
68             world one-import {
69                 import foo: interface {
70                     foo: func();
71                 }
72 
73                 export bar: func();
74             }
75         ",
76     });
77 
78     #[test]
79     fn run() -> Result<()> {
80         let engine = engine();
81 
82         let component = Component::new(
83             &engine,
84             r#"
85                 (component
86                     (import "foo" (instance $i
87                         (export "foo" (func))
88                     ))
89                     (core module $m
90                         (import "" "" (func))
91                         (export "" (func 0))
92                     )
93                     (core func $f (canon lower (func $i "foo")))
94                     (core instance $i (instantiate $m
95                         (with "" (instance (export "" (func $f))))
96                     ))
97 
98                     (func $f (export "bar") (canon lift (core func $i "")))
99                 )
100             "#,
101         )?;
102 
103         #[derive(Default)]
104         struct MyImports {
105             hit: bool,
106         }
107 
108         impl foo::Host for MyImports {
109             fn foo(&mut self) {
110                 self.hit = true;
111             }
112         }
113 
114         let mut linker = Linker::new(&engine);
115         foo::add_to_linker(&mut linker, |f: &mut MyImports| f)?;
116         let mut store = Store::new(&engine, MyImports::default());
117         let one_import = OneImport::instantiate(&mut store, &component, &linker)?;
118         one_import.call_bar(&mut store)?;
119         assert!(store.data().hit);
120         Ok(())
121     }
122 }
123 
124 mod resources_at_world_level {
125     use super::*;
126     use wasmtime::component::Resource;
127 
128     wasmtime::component::bindgen!({
129         inline: "
130             package foo:foo;
131 
132             world resources {
133                 resource x {
134                     constructor();
135                 }
136 
137                 export y: func(x: x);
138             }
139         ",
140     });
141 
142     #[test]
143     fn run() -> Result<()> {
144         let engine = engine();
145 
146         let component = Component::new(
147             &engine,
148             r#"
149                 (component
150                     (import "x" (type $x (sub resource)))
151                     (import "[constructor]x" (func $ctor (result (own $x))))
152 
153                     (core func $dtor (canon resource.drop $x))
154                     (core func $ctor (canon lower (func $ctor)))
155 
156                     (core module $m
157                         (import "" "ctor" (func $ctor (result i32)))
158                         (import "" "dtor" (func $dtor (param i32)))
159 
160                         (func (export "x") (param i32)
161                             (call $dtor (local.get 0))
162                             (call $dtor (call $ctor))
163                         )
164                     )
165                     (core instance $i (instantiate $m
166                         (with "" (instance
167                             (export "ctor" (func $ctor))
168                             (export "dtor" (func $dtor))
169                         ))
170                     ))
171                     (func (export "y") (param "x" (own $x))
172                         (canon lift (core func $i "x")))
173                 )
174             "#,
175         )?;
176 
177         #[derive(Default)]
178         struct MyImports {
179             ctor_hit: bool,
180             drops: usize,
181         }
182 
183         impl HostX for MyImports {
184             fn new(&mut self) -> Resource<X> {
185                 self.ctor_hit = true;
186                 Resource::new_own(80)
187             }
188 
189             fn drop(&mut self, val: Resource<X>) -> Result<()> {
190                 match self.drops {
191                     0 => assert_eq!(val.rep(), 40),
192                     1 => assert_eq!(val.rep(), 80),
193                     _ => unreachable!(),
194                 }
195                 self.drops += 1;
196                 Ok(())
197             }
198         }
199 
200         impl ResourcesImports for MyImports {}
201 
202         let mut linker = Linker::new(&engine);
203         Resources::add_to_linker(&mut linker, |f: &mut MyImports| f)?;
204         let mut store = Store::new(&engine, MyImports::default());
205         let one_import = Resources::instantiate(&mut store, &component, &linker)?;
206         one_import.call_y(&mut store, Resource::new_own(40))?;
207         assert!(store.data().ctor_hit);
208         assert_eq!(store.data().drops, 2);
209         Ok(())
210     }
211 }
212 
213 mod resources_at_interface_level {
214     use super::*;
215     use wasmtime::component::Resource;
216 
217     wasmtime::component::bindgen!({
218         inline: "
219             package foo:foo;
220 
221             interface def {
222                 resource x {
223                     constructor();
224                 }
225             }
226 
227             interface user {
228                 use def.{x};
229 
230                 y: func(x: x);
231             }
232 
233             world resources {
234                 export user;
235             }
236         ",
237     });
238 
239     #[test]
240     fn run() -> Result<()> {
241         let engine = engine();
242 
243         let component = Component::new(
244             &engine,
245             r#"
246                 (component
247                     (import (interface "foo:foo/def") (instance $i
248                         (export $x "x" (type (sub resource)))
249                         (export "[constructor]x" (func (result (own $x))))
250                     ))
251                     (alias export $i "x" (type $x))
252                     (core func $dtor (canon resource.drop $x))
253                     (core func $ctor (canon lower (func $i "[constructor]x")))
254 
255                     (core module $m
256                         (import "" "ctor" (func $ctor (result i32)))
257                         (import "" "dtor" (func $dtor (param i32)))
258 
259                         (func (export "x") (param i32)
260                             (call $dtor (local.get 0))
261                             (call $dtor (call $ctor))
262                         )
263                     )
264                     (core instance $i (instantiate $m
265                         (with "" (instance
266                             (export "ctor" (func $ctor))
267                             (export "dtor" (func $dtor))
268                         ))
269                     ))
270                     (func $y (param "x" (own $x))
271                         (canon lift (core func $i "x")))
272 
273                     (instance (export (interface "foo:foo/user"))
274                         (export "y" (func $y))
275                     )
276                 )
277             "#,
278         )?;
279 
280         #[derive(Default)]
281         struct MyImports {
282             ctor_hit: bool,
283             drops: usize,
284         }
285 
286         use foo::foo::def::X;
287 
288         impl foo::foo::def::HostX for MyImports {
289             fn new(&mut self) -> Resource<X> {
290                 self.ctor_hit = true;
291                 Resource::new_own(80)
292             }
293 
294             fn drop(&mut self, val: Resource<X>) -> Result<()> {
295                 match self.drops {
296                     0 => assert_eq!(val.rep(), 40),
297                     1 => assert_eq!(val.rep(), 80),
298                     _ => unreachable!(),
299                 }
300                 self.drops += 1;
301                 Ok(())
302             }
303         }
304 
305         impl foo::foo::def::Host for MyImports {}
306 
307         let mut linker = Linker::new(&engine);
308         Resources::add_to_linker(&mut linker, |f: &mut MyImports| f)?;
309         let mut store = Store::new(&engine, MyImports::default());
310         let one_import = Resources::instantiate(&mut store, &component, &linker)?;
311         one_import
312             .foo_foo_user()
313             .call_y(&mut store, Resource::new_own(40))?;
314         assert!(store.data().ctor_hit);
315         assert_eq!(store.data().drops, 2);
316         Ok(())
317     }
318 }
319 
320 mod async_config {
321     use super::*;
322 
323     wasmtime::component::bindgen!({
324         inline: "
325             package foo:foo;
326 
327             world t1 {
328                 import foo: interface {
329                     foo: func();
330                 }
331                 import x: func();
332                 import y: func();
333                 export z: func();
334             }
335         ",
336         async: true,
337     });
338 
339     struct T;
340 
341     #[async_trait::async_trait]
342     impl T1Imports for T {
343         async fn x(&mut self) {}
344 
345         async fn y(&mut self) {}
346     }
347 
348     async fn _test_t1(t1: &T1, store: &mut Store<()>) {
349         let _ = t1.call_z(&mut *store).await;
350     }
351 
352     wasmtime::component::bindgen!({
353         inline: "
354             package foo:foo;
355 
356             world t2 {
357                 import x: func();
358                 import y: func();
359                 export z: func();
360             }
361         ",
362         async: {
363             except_imports: ["x"],
364         },
365     });
366 
367     #[async_trait::async_trait]
368     impl T2Imports for T {
369         fn x(&mut self) {}
370 
371         async fn y(&mut self) {}
372     }
373 
374     async fn _test_t2(t2: &T2, store: &mut Store<()>) {
375         let _ = t2.call_z(&mut *store).await;
376     }
377 
378     wasmtime::component::bindgen!({
379         inline: "
380             package foo:foo;
381 
382             world t3 {
383                 import x: func();
384                 import y: func();
385                 export z: func();
386             }
387         ",
388         async: {
389             only_imports: ["x"],
390         },
391     });
392 
393     #[async_trait::async_trait]
394     impl T3Imports for T {
395         async fn x(&mut self) {}
396 
397         fn y(&mut self) {}
398     }
399 
400     async fn _test_t3(t3: &T3, store: &mut Store<()>) {
401         let _ = t3.call_z(&mut *store).await;
402     }
403 }
404 
405 mod exported_resources {
406     use super::*;
407     use std::mem;
408     use wasmtime::component::Resource;
409 
410     wasmtime::component::bindgen!({
411         inline: "
412             package foo:foo;
413 
414             interface a {
415                 resource x {
416                     constructor();
417                 }
418             }
419 
420             world resources {
421                 export b: interface {
422                     use a.{x as y};
423 
424                     resource x {
425                         constructor(y: y);
426                         foo: func() -> u32;
427                     }
428                 }
429 
430                 resource x;
431 
432                 export f: func(x1: x, x2: x) -> x;
433             }
434         ",
435     });
436 
437     #[derive(Default)]
438     struct MyImports {
439         hostcalls: Vec<Hostcall>,
440         next_a_x: u32,
441     }
442 
443     #[derive(PartialEq, Debug)]
444     enum Hostcall {
445         DropRootX(u32),
446         DropAX(u32),
447         NewA,
448     }
449 
450     use foo::foo::a;
451 
452     impl ResourcesImports for MyImports {}
453 
454     impl HostX for MyImports {
455         fn drop(&mut self, val: Resource<X>) -> Result<()> {
456             self.hostcalls.push(Hostcall::DropRootX(val.rep()));
457             Ok(())
458         }
459     }
460 
461     impl a::HostX for MyImports {
462         fn new(&mut self) -> Resource<a::X> {
463             let rep = self.next_a_x;
464             self.next_a_x += 1;
465             self.hostcalls.push(Hostcall::NewA);
466             Resource::new_own(rep)
467         }
468 
469         fn drop(&mut self, val: Resource<a::X>) -> Result<()> {
470             self.hostcalls.push(Hostcall::DropAX(val.rep()));
471             Ok(())
472         }
473     }
474 
475     impl foo::foo::a::Host for MyImports {}
476 
477     #[test]
478     fn run() -> Result<()> {
479         let engine = engine();
480 
481         let component = Component::new(
482             &engine,
483             r#"
484 (component
485   ;; setup the `foo:foo/a` import
486   (import (interface "foo:foo/a") (instance $a
487     (export $x "x" (type (sub resource)))
488     (export "[constructor]x" (func (result (own $x))))
489   ))
490   (alias export $a "x" (type $a-x))
491   (core func $a-x-drop (canon resource.drop $a-x))
492   (core func $a-x-ctor (canon lower (func $a "[constructor]x")))
493 
494   ;; setup the root import of the `x` resource
495   (import "x" (type $x (sub resource)))
496   (core func $root-x-dtor (canon resource.drop $x))
497 
498   ;; setup and declare the `x` resource for the `b` export.
499   (core module $indirect-dtor
500     (func (export "b-x-dtor") (param i32)
501       local.get 0
502       i32.const 0
503       call_indirect (param i32)
504     )
505     (table (export "$imports") 1 1 funcref)
506   )
507   (core instance $indirect-dtor (instantiate $indirect-dtor))
508   (type $b-x (resource (rep i32) (dtor (func $indirect-dtor "b-x-dtor"))))
509   (core func $b-x-drop (canon resource.drop $b-x))
510   (core func $b-x-rep (canon resource.rep $b-x))
511   (core func $b-x-new (canon resource.new $b-x))
512 
513   ;; main module implementation
514   (core module $main
515     (import "foo:foo/a" "[constructor]x" (func $a-x-ctor (result i32)))
516     (import "foo:foo/a" "[resource-drop]x" (func $a-x-dtor (param i32)))
517     (import "$root" "[resource-drop]x" (func $x-dtor (param i32)))
518     (import "[export]b" "[resource-drop]x" (func $b-x-dtor (param i32)))
519     (import "[export]b" "[resource-new]x" (func $b-x-new (param i32) (result i32)))
520     (import "[export]b" "[resource-rep]x" (func $b-x-rep (param i32) (result i32)))
521     (func (export "b#[constructor]x") (param i32) (result i32)
522       (call $a-x-dtor (local.get 0))
523       (call $b-x-new (call $a-x-ctor))
524     )
525     (func (export "b#[method]x.foo") (param i32) (result i32)
526       local.get 0)
527     (func (export "b#[dtor]x") (param i32)
528       (call $a-x-dtor (local.get 0))
529     )
530     (func (export "f") (param i32 i32) (result i32)
531       (call $x-dtor (local.get 0))
532       local.get 1
533     )
534   )
535   (core instance $main (instantiate $main
536     (with "foo:foo/a" (instance
537       (export "[resource-drop]x" (func $a-x-drop))
538       (export "[constructor]x" (func $a-x-ctor))
539     ))
540     (with "$root" (instance
541       (export "[resource-drop]x" (func $root-x-dtor))
542     ))
543     (with "[export]b" (instance
544       (export "[resource-drop]x" (func $b-x-drop))
545       (export "[resource-rep]x" (func $b-x-rep))
546       (export "[resource-new]x" (func $b-x-new))
547     ))
548   ))
549 
550   ;; fill in `$indirect-dtor`'s table with the actual destructor definition
551   ;; now that it's available.
552   (core module $fixup
553     (import "" "b-x-dtor" (func $b-x-dtor (param i32)))
554     (import "" "$imports" (table 1 1 funcref))
555     (elem (i32.const 0) func $b-x-dtor)
556   )
557   (core instance (instantiate $fixup
558     (with "" (instance
559       (export "$imports" (table 0 "$imports"))
560       (export "b-x-dtor" (func $main "b#[dtor]x"))
561     ))
562   ))
563 
564   ;; Create the `b` export through a subcomponent instantiation.
565   (func $b-x-ctor (param "y" (own $a-x)) (result (own $b-x))
566     (canon lift (core func $main "b#[constructor]x")))
567   (func $b-x-foo (param "self" (borrow $b-x)) (result u32)
568     (canon lift (core func $main "b#[method]x.foo")))
569   (component $b
570     (import "a-x" (type $y (sub resource)))
571     (import "b-x" (type $x' (sub resource)))
572     (import "ctor" (func $ctor (param "y" (own $y)) (result (own $x'))))
573     (import "foo" (func $foo (param "self" (borrow $x')) (result u32)))
574     (export $x "x" (type $x'))
575     (export "[constructor]x"
576       (func $ctor)
577       (func (param "y" (own $y)) (result (own $x))))
578     (export "[method]x.foo"
579       (func $foo)
580       (func (param "self" (borrow $x)) (result u32)))
581   )
582   (instance (export "b") (instantiate $b
583     (with "ctor" (func $b-x-ctor))
584     (with "foo" (func $b-x-foo))
585     (with "a-x" (type 0 "x"))
586     (with "b-x" (type $b-x))
587   ))
588 
589   ;; Create the `f` export which is a bare function
590   (func (export "f") (param "x1" (own $x)) (param "x2" (own $x)) (result (own $x))
591     (canon lift (core func $main "f")))
592 )
593             "#,
594         )?;
595 
596         let mut linker = Linker::new(&engine);
597         Resources::add_to_linker(&mut linker, |f: &mut MyImports| f)?;
598         let mut store = Store::new(&engine, MyImports::default());
599         let i = Resources::instantiate(&mut store, &component, &linker)?;
600 
601         // call the root export `f` twice
602         let ret = i.call_f(&mut store, Resource::new_own(1), Resource::new_own(2))?;
603         assert_eq!(ret.rep(), 2);
604         assert_eq!(
605             mem::take(&mut store.data_mut().hostcalls),
606             [Hostcall::DropRootX(1)]
607         );
608         let ret = i.call_f(&mut store, Resource::new_own(3), Resource::new_own(4))?;
609         assert_eq!(ret.rep(), 4);
610         assert_eq!(
611             mem::take(&mut store.data_mut().hostcalls),
612             [Hostcall::DropRootX(3)]
613         );
614 
615         // interact with the `b` export
616         let b = i.b();
617         let b_x = b.x().call_constructor(&mut store, Resource::new_own(5))?;
618         assert_eq!(
619             mem::take(&mut store.data_mut().hostcalls),
620             [Hostcall::DropAX(5), Hostcall::NewA]
621         );
622         b.x().call_foo(&mut store, b_x.clone())?;
623         assert_eq!(mem::take(&mut store.data_mut().hostcalls), []);
624         b_x.resource_drop(&mut store)?;
625         assert_eq!(
626             mem::take(&mut store.data_mut().hostcalls),
627             [Hostcall::DropAX(0)],
628         );
629         Ok(())
630     }
631 }
632