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 x: func();
329                 import y: func();
330                 export z: func();
331             }
332         ",
333         async: true,
334     });
335 
336     struct T;
337 
338     #[async_trait::async_trait]
339     impl T1Imports for T {
340         async fn x(&mut self) {}
341 
342         async fn y(&mut self) {}
343     }
344 
345     async fn _test_t1(t1: &T1, store: &mut Store<()>) {
346         let _ = t1.call_z(&mut *store).await;
347     }
348 
349     wasmtime::component::bindgen!({
350         inline: "
351             package foo:foo;
352 
353             world t2 {
354                 import x: func();
355                 import y: func();
356                 export z: func();
357             }
358         ",
359         async: {
360             except_imports: ["x"],
361         },
362     });
363 
364     #[async_trait::async_trait]
365     impl T2Imports for T {
366         fn x(&mut self) {}
367 
368         async fn y(&mut self) {}
369     }
370 
371     async fn _test_t2(t2: &T2, store: &mut Store<()>) {
372         let _ = t2.call_z(&mut *store).await;
373     }
374 
375     wasmtime::component::bindgen!({
376         inline: "
377             package foo:foo;
378 
379             world t3 {
380                 import x: func();
381                 import y: func();
382                 export z: func();
383             }
384         ",
385         async: {
386             only_imports: ["x"],
387         },
388     });
389 
390     #[async_trait::async_trait]
391     impl T3Imports for T {
392         async fn x(&mut self) {}
393 
394         fn y(&mut self) {}
395     }
396 
397     async fn _test_t3(t3: &T3, store: &mut Store<()>) {
398         let _ = t3.call_z(&mut *store).await;
399     }
400 }
401 
402 mod exported_resources {
403     use super::*;
404     use std::mem;
405     use wasmtime::component::Resource;
406 
407     wasmtime::component::bindgen!({
408         inline: "
409             package foo:foo;
410 
411             interface a {
412                 resource x {
413                     constructor();
414                 }
415             }
416 
417             world resources {
418                 export b: interface {
419                     use a.{x as y};
420 
421                     resource x {
422                         constructor(y: y);
423                         foo: func() -> u32;
424                     }
425                 }
426 
427                 resource x;
428 
429                 export f: func(x1: x, x2: x) -> x;
430             }
431         ",
432     });
433 
434     #[derive(Default)]
435     struct MyImports {
436         hostcalls: Vec<Hostcall>,
437         next_a_x: u32,
438     }
439 
440     #[derive(PartialEq, Debug)]
441     enum Hostcall {
442         DropRootX(u32),
443         DropAX(u32),
444         NewA,
445     }
446 
447     use foo::foo::a;
448 
449     impl ResourcesImports for MyImports {}
450 
451     impl HostX for MyImports {
452         fn drop(&mut self, val: Resource<X>) -> Result<()> {
453             self.hostcalls.push(Hostcall::DropRootX(val.rep()));
454             Ok(())
455         }
456     }
457 
458     impl a::HostX for MyImports {
459         fn new(&mut self) -> Resource<a::X> {
460             let rep = self.next_a_x;
461             self.next_a_x += 1;
462             self.hostcalls.push(Hostcall::NewA);
463             Resource::new_own(rep)
464         }
465 
466         fn drop(&mut self, val: Resource<a::X>) -> Result<()> {
467             self.hostcalls.push(Hostcall::DropAX(val.rep()));
468             Ok(())
469         }
470     }
471 
472     impl foo::foo::a::Host for MyImports {}
473 
474     #[test]
475     fn run() -> Result<()> {
476         let engine = engine();
477 
478         let component = Component::new(
479             &engine,
480             r#"
481 (component
482   ;; setup the `foo:foo/a` import
483   (import (interface "foo:foo/a") (instance $a
484     (export $x "x" (type (sub resource)))
485     (export "[constructor]x" (func (result (own $x))))
486   ))
487   (alias export $a "x" (type $a-x))
488   (core func $a-x-drop (canon resource.drop $a-x))
489   (core func $a-x-ctor (canon lower (func $a "[constructor]x")))
490 
491   ;; setup the root import of the `x` resource
492   (import "x" (type $x (sub resource)))
493   (core func $root-x-dtor (canon resource.drop $x))
494 
495   ;; setup and declare the `x` resource for the `b` export.
496   (core module $indirect-dtor
497     (func (export "b-x-dtor") (param i32)
498       local.get 0
499       i32.const 0
500       call_indirect (param i32)
501     )
502     (table (export "$imports") 1 1 funcref)
503   )
504   (core instance $indirect-dtor (instantiate $indirect-dtor))
505   (type $b-x (resource (rep i32) (dtor (func $indirect-dtor "b-x-dtor"))))
506   (core func $b-x-drop (canon resource.drop $b-x))
507   (core func $b-x-rep (canon resource.rep $b-x))
508   (core func $b-x-new (canon resource.new $b-x))
509 
510   ;; main module implementation
511   (core module $main
512     (import "foo:foo/a" "[constructor]x" (func $a-x-ctor (result i32)))
513     (import "foo:foo/a" "[resource-drop]x" (func $a-x-dtor (param i32)))
514     (import "$root" "[resource-drop]x" (func $x-dtor (param i32)))
515     (import "[export]b" "[resource-drop]x" (func $b-x-dtor (param i32)))
516     (import "[export]b" "[resource-new]x" (func $b-x-new (param i32) (result i32)))
517     (import "[export]b" "[resource-rep]x" (func $b-x-rep (param i32) (result i32)))
518     (func (export "b#[constructor]x") (param i32) (result i32)
519       (call $a-x-dtor (local.get 0))
520       (call $b-x-new (call $a-x-ctor))
521     )
522     (func (export "b#[method]x.foo") (param i32) (result i32)
523       local.get 0)
524     (func (export "b#[dtor]x") (param i32)
525       (call $a-x-dtor (local.get 0))
526     )
527     (func (export "f") (param i32 i32) (result i32)
528       (call $x-dtor (local.get 0))
529       local.get 1
530     )
531   )
532   (core instance $main (instantiate $main
533     (with "foo:foo/a" (instance
534       (export "[resource-drop]x" (func $a-x-drop))
535       (export "[constructor]x" (func $a-x-ctor))
536     ))
537     (with "$root" (instance
538       (export "[resource-drop]x" (func $root-x-dtor))
539     ))
540     (with "[export]b" (instance
541       (export "[resource-drop]x" (func $b-x-drop))
542       (export "[resource-rep]x" (func $b-x-rep))
543       (export "[resource-new]x" (func $b-x-new))
544     ))
545   ))
546 
547   ;; fill in `$indirect-dtor`'s table with the actual destructor definition
548   ;; now that it's available.
549   (core module $fixup
550     (import "" "b-x-dtor" (func $b-x-dtor (param i32)))
551     (import "" "$imports" (table 1 1 funcref))
552     (elem (i32.const 0) func $b-x-dtor)
553   )
554   (core instance (instantiate $fixup
555     (with "" (instance
556       (export "$imports" (table 0 "$imports"))
557       (export "b-x-dtor" (func $main "b#[dtor]x"))
558     ))
559   ))
560 
561   ;; Create the `b` export through a subcomponent instantiation.
562   (func $b-x-ctor (param "y" (own $a-x)) (result (own $b-x))
563     (canon lift (core func $main "b#[constructor]x")))
564   (func $b-x-foo (param "self" (borrow $b-x)) (result u32)
565     (canon lift (core func $main "b#[method]x.foo")))
566   (component $b
567     (import "a-x" (type $y (sub resource)))
568     (import "b-x" (type $x' (sub resource)))
569     (import "ctor" (func $ctor (param "y" (own $y)) (result (own $x'))))
570     (import "foo" (func $foo (param "self" (borrow $x')) (result u32)))
571     (export $x "x" (type $x'))
572     (export "[constructor]x"
573       (func $ctor)
574       (func (param "y" (own $y)) (result (own $x))))
575     (export "[method]x.foo"
576       (func $foo)
577       (func (param "self" (borrow $x)) (result u32)))
578   )
579   (instance (export "b") (instantiate $b
580     (with "ctor" (func $b-x-ctor))
581     (with "foo" (func $b-x-foo))
582     (with "a-x" (type 0 "x"))
583     (with "b-x" (type $b-x))
584   ))
585 
586   ;; Create the `f` export which is a bare function
587   (func (export "f") (param "x1" (own $x)) (param "x2" (own $x)) (result (own $x))
588     (canon lift (core func $main "f")))
589 )
590             "#,
591         )?;
592 
593         let mut linker = Linker::new(&engine);
594         Resources::add_to_linker(&mut linker, |f: &mut MyImports| f)?;
595         let mut store = Store::new(&engine, MyImports::default());
596         let (i, _) = Resources::instantiate(&mut store, &component, &linker)?;
597 
598         // call the root export `f` twice
599         let ret = i.call_f(&mut store, Resource::new_own(1), Resource::new_own(2))?;
600         assert_eq!(ret.rep(), 2);
601         assert_eq!(
602             mem::take(&mut store.data_mut().hostcalls),
603             [Hostcall::DropRootX(1)]
604         );
605         let ret = i.call_f(&mut store, Resource::new_own(3), Resource::new_own(4))?;
606         assert_eq!(ret.rep(), 4);
607         assert_eq!(
608             mem::take(&mut store.data_mut().hostcalls),
609             [Hostcall::DropRootX(3)]
610         );
611 
612         // interact with the `b` export
613         let b = i.b();
614         let b_x = b.x().call_constructor(&mut store, Resource::new_own(5))?;
615         assert_eq!(
616             mem::take(&mut store.data_mut().hostcalls),
617             [Hostcall::DropAX(5), Hostcall::NewA]
618         );
619         b.x().call_foo(&mut store, b_x.clone())?;
620         assert_eq!(mem::take(&mut store.data_mut().hostcalls), []);
621         b_x.resource_drop(&mut store)?;
622         assert_eq!(
623             mem::take(&mut store.data_mut().hostcalls),
624             [Hostcall::DropAX(0)],
625         );
626         Ok(())
627     }
628 }
629