1 #include "utils.h"
2 
3 #include <gtest/gtest.h>
4 #include <wasmtime.h>
5 #include <wasmtime/component.hh>
6 #include <wasmtime/store.hh>
7 
8 #include <array>
9 #include <format>
10 #include <optional>
11 #include <span>
12 #include <variant>
13 
14 using namespace wasmtime::component;
15 using wasmtime::Engine;
16 using wasmtime::Result;
17 using wasmtime::Span;
18 using wasmtime::Store;
19 
echo_component(std::string_view type,std::string_view func,std::string_view host_params)20 static std::string echo_component(std::string_view type, std::string_view func,
21                                   std::string_view host_params) {
22   return std::format(
23       R"END(
24 (component
25 	(type $Foo' {})
26 	(import "foo" (type $Foo (eq $Foo')))
27 	(import "do" (func $do (param "a" $Foo) (result $Foo)))
28 	(core module $libc
29 		(memory (export "memory") 1)
30 		{}
31 	)
32 	(core instance $libc (instantiate $libc))
33 	(core func $do_lower (canon lower (func $do) (memory $libc "memory") (realloc (func $libc "realloc"))))
34 
35 	(core module $doer
36 		(import "host" "do" (func $do {}))
37 		(import "libc" "memory" (memory 1))
38 		(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
39 
40 		(func (export "call")
41 			{})
42 	)
43 	(core instance $doer (instantiate $doer
44 		(with "host" (instance (export "do" (func $do_lower))))
45 		(with "libc" (instance $libc))
46 	))
47 
48 	(func $call
49 		(param "a" $Foo)
50 		(result $Foo)
51 		(canon lift
52 			(core func $doer "call")
53 			(memory $libc "memory")
54 			(realloc (func $libc "realloc")))
55 	)
56 
57 	(export "call" (func $call))
58 )
59 		  )END",
60       type, REALLOC_AND_FREE, host_params, func);
61 }
62 
63 struct Context {
64   Store store;
65   Store::Context context;
66   Instance instance;
67   Func func;
68 
NewContext69   static Context New(Engine &engine, std::string_view component_text,
70                      Linker &linker) {
71     Store store(engine);
72     const auto context = store.context();
73     Component component = Component::compile(engine, component_text).unwrap();
74 
75     auto f = component.export_index(nullptr, "call");
76 
77     EXPECT_TRUE(f);
78 
79     auto instance = linker.instantiate(context, component).unwrap();
80     auto func = *instance.get_func(context, *f);
81 
82     return Context{
83         .store = std::move(store),
84         .context = context,
85         .instance = instance,
86         .func = func,
87     };
88   }
89 };
90 
91 typedef Result<std::monostate> (*host_func_t)(Store::Context, const FuncType &,
92                                               Span<const Val>, Span<Val>);
93 
create(std::string_view type,std::string_view body,std::string_view host_params,host_func_t callback)94 static Context create(std::string_view type, std::string_view body,
95                       std::string_view host_params, host_func_t callback) {
96   Engine engine;
97   Linker linker(engine);
98   linker.root().add_func("do", callback).unwrap();
99   auto component_text = echo_component(type, body, host_params);
100   return Context::New(engine, component_text, linker);
101 }
102 
TEST(component,value_record)103 TEST(component, value_record) {
104   static const auto check = [](const Val &v, uint64_t x, uint64_t y) {
105     EXPECT_TRUE(v.is_record());
106     const Record &r = v.get_record();
107     EXPECT_EQ(r.size(), 2);
108 
109     const auto &x_field = *r.begin();
110     EXPECT_EQ(x_field.name(), "x");
111     const auto &x_field_val = x_field.value();
112     EXPECT_TRUE(x_field_val.is_u64());
113     EXPECT_EQ(x_field_val.get_u64(), x);
114 
115     const auto &y_field = *(r.begin() + 1);
116     EXPECT_EQ(y_field.name(), "y");
117     const auto &y_field_val = y_field.value();
118     EXPECT_TRUE(y_field_val.is_u64());
119     EXPECT_EQ(y_field_val.get_u64(), y);
120   };
121 
122   static const auto make = [](uint64_t x, uint64_t y) -> Val {
123     return Record({
124         {"x", x},
125         {"y", y},
126     });
127   };
128 
129   auto ctx = create(
130       R"((record (field "x" u64) (field "y" u64)))", R"(
131 (param $x i64)
132 (param $y i64)
133 (result i32)
134 (local $res i32)
135 local.get $x
136 local.get $y
137 (call $realloc
138 	(i32.const 0)
139 	(i32.const 0)
140 	(i32.const 4)
141 	(i32.const 16))
142 local.tee $res
143 call $do
144 local.get $res
145 	  )",
146       "(param i64 i64 i32)",
147       +[](Store::Context, const FuncType &_ty, Span<const Val> args,
148           Span<Val> rets) -> Result<std::monostate> {
149         EXPECT_EQ(args.size(), 1);
150         check(args[0], 1, 2);
151 
152         EXPECT_EQ(rets.size(), 1);
153         rets[0] = make(3, 4);
154 
155         return std::monostate();
156       });
157 
158   auto arg = make(1, 2);
159   auto res = Val(false);
160 
161   ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))
162       .unwrap();
163   ctx.func.post_return(ctx.context).unwrap();
164 
165   check(res, 3, 4);
166 }
167 
TEST(component,value_string)168 TEST(component, value_string) {
169   static const auto check = [](const Val &v, std::string_view text) {
170     EXPECT_TRUE(v.is_string());
171     EXPECT_EQ(v.get_string(), text);
172   };
173 
174   static const auto make = [](std::string_view text) -> Val {
175     return Val::string(text);
176   };
177 
178   auto ctx = create(
179       R"(string)", R"(
180 (param $x i32)
181 (param $y i32)
182 (result i32)
183 (local $res i32)
184 local.get $x
185 local.get $y
186 (call $realloc
187 	(i32.const 0)
188 	(i32.const 0)
189 	(i32.const 4)
190 	(i32.const 8))
191 local.tee $res
192 call $do
193 local.get $res
194 	  )",
195       "(param i32 i32 i32)",
196       +[](Store::Context, const FuncType &, Span<const Val> args,
197           Span<Val> rets) -> Result<std::monostate> {
198         EXPECT_EQ(args.size(), 1);
199         check(args[0], "hello from A!");
200 
201         EXPECT_EQ(rets.size(), 1);
202         rets[0] = make("hello from B!");
203 
204         return std::monostate();
205       });
206 
207   auto arg = make("hello from A!");
208   auto res = Val(false);
209 
210   ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))
211       .unwrap();
212   ctx.func.post_return(ctx.context).unwrap();
213 
214   check(res, "hello from B!");
215 }
216 
TEST(component,value_list)217 TEST(component, value_list) {
218   static const auto check = [](const Val &v, std::vector<uint32_t> data) {
219     EXPECT_TRUE(v.is_list());
220     const List &l = v.get_list();
221     EXPECT_EQ(l.size(), data.size());
222 
223     for (auto i = 0; i < data.size(); i++) {
224       const auto &elem = l.begin()[i];
225       EXPECT_TRUE(elem.is_u32());
226       EXPECT_EQ(elem.get_u32(), data[i]);
227     }
228   };
229 
230   static const auto make = [](std::vector<Val> data) -> Val {
231     return List(data);
232   };
233 
234   auto ctx = create(
235       R"((list u32))", R"(
236 (param $x i32)
237 (param $y i32)
238 (result i32)
239 (local $res i32)
240 local.get $x
241 local.get $y
242 (call $realloc
243 	(i32.const 0)
244 	(i32.const 0)
245 	(i32.const 4)
246 	(i32.const 8))
247 local.tee $res
248 call $do
249 local.get $res
250 	  )",
251       "(param i32 i32 i32)",
252       +[](Store::Context, const FuncType &, Span<const Val> args,
253           Span<Val> rets) -> Result<std::monostate> {
254         EXPECT_EQ(args.size(), 1);
255         check(args[0], {1, 2, 3});
256 
257         EXPECT_EQ(rets.size(), 1);
258         rets[0] = make({uint32_t(4), uint32_t(5), uint32_t(6), uint32_t(7)});
259 
260         return std::monostate();
261       });
262 
263   auto arg = make({uint32_t(1), uint32_t(2), uint32_t(3)});
264   auto res = Val(false);
265 
266   ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))
267       .unwrap();
268   ctx.func.post_return(ctx.context).unwrap();
269 
270   check(res, {4, 5, 6, 7});
271 }
272 
TEST(component,value_tuple)273 TEST(component, value_tuple) {
274   static const auto check = [](const Val &v, std::vector<uint32_t> data) {
275     EXPECT_TRUE(v.is_tuple());
276     const Tuple &t = v.get_tuple();
277     EXPECT_EQ(t.size(), data.size());
278     for (auto i = 0; i < data.size(); i++) {
279       const auto &elem = t.begin()[i];
280       EXPECT_TRUE(elem.is_u32());
281       EXPECT_EQ(elem.get_u32(), data[i]);
282     }
283   };
284 
285   static const auto make = [](std::vector<Val> data) -> Val {
286     return Tuple(data);
287   };
288 
289   auto ctx = create(
290       R"((tuple u32 u32 u32))", R"(
291 (param $x i32)
292 (param $y i32)
293 (param $z i32)
294 (result i32)
295 (local $res i32)
296 local.get $x
297 local.get $y
298 local.get $z
299 (call $realloc
300 	(i32.const 0)
301 	(i32.const 0)
302 	(i32.const 4)
303 	(i32.const 12))
304 local.tee $res
305 call $do
306 local.get $res
307 	  )",
308       "(param i32 i32 i32 i32)",
309       +[](Store::Context, const FuncType &, Span<const Val> args,
310           Span<Val> rets) -> Result<std::monostate> {
311         EXPECT_EQ(args.size(), 1);
312         check(args[0], {1, 2, 3});
313 
314         EXPECT_EQ(rets.size(), 1);
315         rets[0] = make({uint32_t(4), uint32_t(5), uint32_t(6)});
316 
317         return std::monostate();
318       });
319 
320   auto arg = make({uint32_t(1), uint32_t(2), uint32_t(3)});
321   auto res = Val(false);
322 
323   ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))
324       .unwrap();
325   ctx.func.post_return(ctx.context).unwrap();
326 
327   check(res, {4, 5, 6});
328 }
329 
TEST(component,value_variant)330 TEST(component, value_variant) {
331   static const auto check_aa = [](const Val &v, uint32_t value) {
332     EXPECT_TRUE(v.is_variant());
333     const Variant &var = v.get_variant();
334     EXPECT_EQ(var.discriminant(), "aa");
335     EXPECT_NE(var.value(), nullptr);
336     EXPECT_TRUE(var.value()->is_u32());
337     EXPECT_EQ(var.value()->get_u32(), value);
338   };
339 
340   static const auto check_bb = [](const Val &v, std::string_view value) {
341     EXPECT_TRUE(v.is_variant());
342     const Variant &var = v.get_variant();
343     EXPECT_EQ(var.discriminant(), "bb");
344     EXPECT_NE(var.value(), nullptr);
345     EXPECT_TRUE(var.value()->is_string());
346     EXPECT_EQ(var.value()->get_string(), value);
347   };
348 
349   static const auto make_aa = [](uint32_t value) -> Val {
350     return Variant("aa", Val(value));
351   };
352 
353   static const auto make_bb = [](std::string_view value) -> Val {
354     return Variant("bb", Val::string(value));
355   };
356 
357   auto ctx = create(
358       R"(
359 (variant
360 	(case "aa" u32)
361 	(case "bb" string)
362 )
363 	  )",
364       R"(
365 (param $x i32)
366 (param $y i32)
367 (param $z i32)
368 (result i32)
369 (local $res i32)
370 local.get $x
371 local.get $y
372 local.get $z
373 (call $realloc
374 	(i32.const 0)
375 	(i32.const 0)
376 	(i32.const 4)
377 	(i32.const 12))
378 local.tee $res
379 call $do
380 local.get $res
381 	  )",
382       "(param i32 i32 i32 i32)",
383       +[](Store::Context, const FuncType &, Span<const Val> args,
384           Span<Val> rets) -> Result<std::monostate> {
385         EXPECT_EQ(args.size(), 1);
386         check_aa(args[0], 123);
387 
388         EXPECT_EQ(rets.size(), 1);
389         rets[0] = make_bb("textt");
390 
391         return std::monostate();
392       });
393 
394   auto arg = make_aa(123);
395   auto res = Val(false);
396 
397   ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))
398       .unwrap();
399   ctx.func.post_return(ctx.context).unwrap();
400 
401   check_bb(res, "textt");
402 }
403 
TEST(component,value_enum)404 TEST(component, value_enum) {
405   static const auto check = [](const Val &v, std::string_view text) {
406     EXPECT_TRUE(v.is_enum());
407     EXPECT_EQ(v.get_enum(), text);
408   };
409 
410   static const auto make = [](std::string_view text) -> Val {
411     return Val::enum_(text);
412   };
413 
414   auto ctx = create(
415       R"((enum "aa" "bb"))", R"(
416 (param $x i32)
417 (result i32)
418 local.get $x
419 call $do
420 	  )",
421       "(param i32) (result i32)",
422       +[](Store::Context, const FuncType &, Span<const Val> args,
423           Span<Val> rets) -> Result<std::monostate> {
424         EXPECT_EQ(args.size(), 1);
425         check(args[0], "aa");
426 
427         EXPECT_EQ(rets.size(), 1);
428         rets[0] = make("bb");
429 
430         return std::monostate();
431       });
432 
433   auto arg = make("aa");
434   auto res = Val(false);
435 
436   ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))
437       .unwrap();
438   ctx.func.post_return(ctx.context).unwrap();
439 
440   check(res, "bb");
441 }
442 
TEST(component,value_option)443 TEST(component, value_option) {
444   static const auto check = [](const Val &v, std::optional<uint32_t> value) {
445     EXPECT_TRUE(v.is_option());
446     const WitOption &o = v.get_option();
447     if (value.has_value()) {
448       EXPECT_NE(o.value(), nullptr);
449       EXPECT_TRUE(o.value()->is_u32());
450       EXPECT_EQ(o.value()->get_u32(), *value);
451     } else {
452       EXPECT_EQ(o.value(), nullptr);
453     }
454   };
455 
456   static const auto make = [](std::optional<uint32_t> value) -> Val {
457     if (value) {
458       return WitOption(Val(*value));
459     }
460     return WitOption(std::nullopt);
461   };
462 
463   auto ctx = create(
464       R"((option u32))", R"(
465 (param $x i32)
466 (param $y i32)
467 (result i32)
468 (local $res i32)
469 local.get $x
470 local.get $y
471 (call $realloc
472 	(i32.const 0)
473 	(i32.const 0)
474 	(i32.const 4)
475 	(i32.const 8))
476 local.tee $res
477 call $do
478 local.get $res
479 	  )",
480       "(param i32 i32 i32)",
481       +[](Store::Context, const FuncType &, Span<const Val> args,
482           Span<Val> rets) -> Result<std::monostate> {
483         EXPECT_EQ(args.size(), 1);
484         check(args[0], 123);
485 
486         EXPECT_EQ(rets.size(), 1);
487         rets[0] = make({});
488 
489         return std::monostate();
490       });
491 
492   auto arg = make(123);
493   auto res = Val(false);
494 
495   ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))
496       .unwrap();
497   ctx.func.post_return(ctx.context).unwrap();
498 
499   check(res, {});
500 }
501 
TEST(component,value_result)502 TEST(component, value_result) {
503   static const auto check = [](const Val &v, bool expected_is_ok,
504                                uint32_t expected_value) {
505     EXPECT_TRUE(v.is_result());
506     const WitResult &r = v.get_result();
507     EXPECT_EQ(r.is_ok(), expected_is_ok);
508     EXPECT_NE(r.payload(), nullptr);
509     EXPECT_TRUE(r.payload()->is_u32());
510     EXPECT_EQ(r.payload()->get_u32(), expected_value);
511   };
512 
513   static const auto make = [](bool is_ok, uint32_t value) -> Val {
514     if (is_ok) {
515       return WitResult::ok(Val(value));
516     }
517     return WitResult::err(Val(value));
518   };
519 
520   auto ctx = create(
521       R"((result u32 (error u32)))", R"(
522 (param $x i32)
523 (param $y i32)
524 (result i32)
525 (local $res i32)
526 local.get $x
527 local.get $y
528 (call $realloc
529 	(i32.const 0)
530 	(i32.const 0)
531 	(i32.const 4)
532 	(i32.const 8))
533 local.tee $res
534 call $do
535 local.get $res
536 	  )",
537       "(param i32 i32 i32)",
538       +[](Store::Context, const FuncType &, Span<const Val> args,
539           Span<Val> rets) -> Result<std::monostate> {
540         EXPECT_EQ(args.size(), 1);
541         check(args[0], true, 123);
542 
543         EXPECT_EQ(rets.size(), 1);
544         rets[0] = make(false, 456);
545 
546         return std::monostate();
547       });
548 
549   auto arg = make(true, 123);
550   auto res = Val(false);
551 
552   ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))
553       .unwrap();
554   ctx.func.post_return(ctx.context).unwrap();
555 
556   check(res, false, 456);
557 }
558 
TEST(component,value_flags)559 TEST(component, value_flags) {
560   static const auto check = [](const Val &v, std::vector<std::string> data) {
561     EXPECT_TRUE(v.is_flags());
562     const Flags &f = v.get_flags();
563 
564     EXPECT_EQ(f.size(), data.size());
565     for (auto i = 0; i < data.size(); i++) {
566       EXPECT_EQ(f.begin()[i].name(), data[i]);
567     }
568   };
569 
570   static const auto make = [](std::vector<Flag> data) -> Val {
571     return Flags(data);
572   };
573 
574   auto ctx = create(
575       R"((flags "aa" "bb"))", R"(
576 (param $x i32)
577 (result i32)
578 local.get $x
579 call $do
580 	  )",
581       "(param i32) (result i32)",
582       +[](Store::Context, const FuncType &, Span<const Val> args,
583           Span<Val> rets) -> Result<std::monostate> {
584         EXPECT_EQ(args.size(), 1);
585         check(args[0], {"aa"});
586 
587         EXPECT_EQ(rets.size(), 1);
588         rets[0] = make({Flag("aa"), Flag("bb")});
589 
590         return std::monostate();
591       });
592 
593   auto arg = make({Flag("aa")});
594   auto res = Val(false);
595 
596   ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))
597       .unwrap();
598   ctx.func.post_return(ctx.context).unwrap();
599 
600   check(res, {"aa", "bb"});
601 }
602 
TEST(component,value_list_inner)603 TEST(component, value_list_inner) {
604   auto x = wasmtime_component_val_t{
605       .kind = WASMTIME_COMPONENT_LIST,
606   };
607   wasmtime_component_vallist_new_empty(&x.of.list);
608   EXPECT_EQ(x.of.list.data, nullptr);
609   EXPECT_EQ(x.of.list.size, 0);
610 
611   wasmtime_component_vallist_new_uninit(&x.of.list, 1);
612   EXPECT_NE(x.of.list.data, nullptr);
613   EXPECT_EQ(x.of.list.size, 1);
614 
615   wasmtime_component_vallist_delete(&x.of.list);
616 
617   auto items = std::array{
618       wasmtime_component_val_t{
619           .kind = WASMTIME_COMPONENT_U32,
620           .of = {.u32 = 123},
621       },
622   };
623 
624   wasmtime_component_vallist_new(&x.of.list, items.size(), items.data());
625   EXPECT_NE(x.of.list.data, nullptr);
626   EXPECT_EQ(x.of.list.size, 1);
627 
628   EXPECT_EQ(x.of.list.data[0].kind, WASMTIME_COMPONENT_U32);
629   EXPECT_EQ(x.of.list.data[0].of.u32, 123);
630 
631   auto clone = wasmtime_component_val_t{
632       .kind = WASMTIME_COMPONENT_LIST,
633   };
634 
635   wasmtime_component_vallist_copy(&clone.of.list, &x.of.list);
636   wasmtime_component_vallist_delete(&x.of.list);
637 
638   EXPECT_NE(clone.of.list.data, nullptr);
639   EXPECT_EQ(clone.of.list.size, 1);
640 
641   EXPECT_EQ(clone.of.list.data[0].kind, WASMTIME_COMPONENT_U32);
642   EXPECT_EQ(clone.of.list.data[0].of.u32, 123);
643 
644   wasmtime_component_vallist_delete(&clone.of.list);
645 }
646 
TEST(component,records)647 TEST(component, records) {
648   Record r({{"x", uint64_t(1)}, {"y", uint64_t(2)}});
649   EXPECT_EQ(r.size(), 2);
650 
651   for (auto &field : r) {
652     if (field.name() == "x") {
653       EXPECT_EQ(field.value().get_u64(), 1);
654     } else if (field.name() == "y") {
655       EXPECT_EQ(field.value().get_u64(), 2);
656     } else {
657       FAIL() << "unexpected field name: " << field.name();
658     }
659   }
660 
661   Record r2({{"x", r}, {"y", uint64_t(2)}});
662   EXPECT_EQ(r2.size(), 2);
663   EXPECT_EQ(r.size(), 2);
664 
665   for (auto &field : r2) {
666     if (field.name() == "x") {
667       auto inner = field.value().get_record();
668       EXPECT_EQ(inner.size(), 2);
669       for (auto &inner_field : inner) {
670         if (inner_field.name() == "x") {
671           EXPECT_EQ(inner_field.value().get_u64(), 1);
672         } else if (inner_field.name() == "y") {
673           EXPECT_EQ(inner_field.value().get_u64(), 2);
674         } else {
675           FAIL() << "unexpected inner field name: " << inner_field.name();
676         }
677       }
678     } else if (field.name() == "y") {
679       EXPECT_EQ(field.value().get_u64(), 2);
680     } else {
681       FAIL() << "unexpected field name: " << field.name();
682     }
683   }
684 
685   Val record = r2;
686   EXPECT_TRUE(record.is_record());
687   EXPECT_EQ(r2.size(), 2);
688   Val record2 = std::move(r2);
689   EXPECT_TRUE(record2.is_record());
690   EXPECT_EQ(r2.size(), 0);
691 }
692 
TEST(component,lists)693 TEST(component, lists) {
694   List l({uint32_t(1), uint32_t(2), uint32_t(3)});
695   EXPECT_EQ(l.size(), 3);
696   uint32_t expected = 1;
697   for (auto &val : l) {
698     EXPECT_EQ(val.get_u32(), expected);
699     expected++;
700   }
701 
702   List l2 = l;
703   EXPECT_EQ(l.size(), 3);
704   EXPECT_EQ(l2.size(), 3);
705 
706   List l3 = std::move(l);
707   EXPECT_EQ(l.size(), 0);
708   EXPECT_EQ(l3.size(), 3);
709 
710   Val value(l3);
711   value.get_list();
712 }
713 
TEST(component,tuples)714 TEST(component, tuples) {
715   Tuple l({uint32_t(1), uint64_t(2), uint8_t(3)});
716   EXPECT_EQ(l.size(), 3);
717 
718   Val value(l);
719   EXPECT_TRUE(value.is_tuple());
720   EXPECT_EQ(l.size(), 3);
721 
722   for (auto &val : l) {
723     if (val.is_u32()) {
724       EXPECT_EQ(val.get_u32(), 1);
725     } else if (val.is_u64()) {
726       EXPECT_EQ(val.get_u64(), 2);
727     } else if (val.is_u8()) {
728       EXPECT_EQ(val.get_u8(), 3);
729     } else {
730       FAIL() << "unexpected tuple value type";
731     }
732   }
733 }
734 
TEST(component,variants)735 TEST(component, variants) {
736   Variant v("hello", uint32_t(42));
737   EXPECT_EQ(v.discriminant(), "hello");
738   EXPECT_TRUE(v.value()->is_u32());
739   EXPECT_EQ(v.value()->get_u32(), 42);
740 
741   Variant v2("another", v);
742   EXPECT_EQ(v.discriminant(), "hello");
743   EXPECT_TRUE(v.value()->is_u32());
744   EXPECT_EQ(v.value()->get_u32(), 42);
745   EXPECT_EQ(v2.discriminant(), "another");
746   EXPECT_TRUE(v2.value()->is_variant());
747   auto inner = v2.value()->get_variant();
748   EXPECT_EQ(inner.discriminant(), "hello");
749   EXPECT_TRUE(inner.value()->is_u32());
750   EXPECT_EQ(inner.value()->get_u32(), 42);
751 
752   Val value = v;
753   EXPECT_TRUE(value.is_variant());
754   auto v3 = value.get_variant();
755   EXPECT_EQ(v3.discriminant(), "hello");
756   EXPECT_TRUE(v3.value()->is_u32());
757   EXPECT_EQ(v3.value()->get_u32(), 42);
758 }
759 
TEST(component,strings)760 TEST(component, strings) {
761   Val v = Val::string("hi");
762   EXPECT_TRUE(v.is_string());
763   EXPECT_EQ(v.get_string(), "hi");
764 
765   v = Val::string("another");
766   EXPECT_TRUE(v.is_string());
767   EXPECT_EQ(v.get_string(), "another");
768 }
769 
TEST(component,results)770 TEST(component, results) {
771   WitResult r = WitResult::ok(uint32_t(42));
772   EXPECT_TRUE(r.is_ok());
773   EXPECT_EQ(r.payload()->get_u32(), 42);
774 
775   r = WitResult::ok(std::nullopt);
776   EXPECT_TRUE(r.is_ok());
777   EXPECT_EQ(r.payload(), nullptr);
778 
779   r = WitResult::err(std::nullopt);
780   EXPECT_FALSE(r.is_ok());
781   EXPECT_EQ(r.payload(), nullptr);
782 
783   Val v = r;
784   EXPECT_TRUE(v.is_result());
785   auto r2 = v.get_result();
786   EXPECT_FALSE(r2.is_ok());
787   EXPECT_EQ(r2.payload(), nullptr);
788 
789   r = WitResult::ok(uint32_t(99));
790   v = r;
791   EXPECT_TRUE(r.is_ok());
792   EXPECT_NE(r.payload(), nullptr);
793   EXPECT_EQ(r.payload()->get_u32(), 99);
794 }
795 
TEST(component,enums)796 TEST(component, enums) {
797   Val v = Val::enum_("hi");
798   EXPECT_TRUE(v.is_enum());
799   EXPECT_EQ(v.get_enum(), "hi");
800 
801   v = Val::enum_("another");
802   EXPECT_TRUE(v.is_enum());
803   EXPECT_EQ(v.get_enum(), "another");
804 }
805 
TEST(component,options)806 TEST(component, options) {
807   WitOption o(Val(uint32_t(42)));
808   EXPECT_NE(o.value(), nullptr);
809   EXPECT_TRUE(o.value()->is_u32());
810   EXPECT_EQ(o.value()->get_u32(), 42);
811 
812   Val v(o);
813   WitOption o2(v);
814   EXPECT_NE(o.value(), nullptr);
815   EXPECT_TRUE(o2.value()->is_option());
816   auto inner = o2.value()->get_option();
817   auto value = inner.value();
818   EXPECT_NE(value, nullptr);
819   EXPECT_TRUE(value->is_u32());
820   EXPECT_EQ(value->get_u32(), 42);
821 
822   EXPECT_NE(o.value(), nullptr);
823   EXPECT_TRUE(o.value()->is_u32());
824   EXPECT_EQ(o.value()->get_u32(), 42);
825 
826   WitOption o3(std::nullopt);
827   EXPECT_EQ(o3.value(), nullptr);
828 }
829 
TEST(component,flags)830 TEST(component, flags) {
831   std::vector<Flag> flags = {
832       Flag("a"),
833       Flag("b"),
834       Flag("c"),
835   };
836   Flags f(flags);
837   EXPECT_EQ(f.size(), 3);
838   for (auto i = 0; i < f.size(); i++) {
839     EXPECT_EQ(f.begin()[i].name(), flags[i].name());
840   }
841 
842   flags.clear();
843   Flags f2(flags);
844   EXPECT_EQ(f2.size(), 0);
845   EXPECT_EQ(f.size(), 3);
846 
847   Val v = f;
848   EXPECT_TRUE(v.is_flags());
849   Flags f3 = v.get_flags();
850   EXPECT_EQ(f3.size(), 3);
851   EXPECT_EQ(f.size(), 3);
852 }
853 
TEST(component,value_host_resource)854 TEST(component, value_host_resource) {
855   static const uint32_t RESOURCE_TYPE = 100;
856 
857   static const auto check = [](Store::Context cx, const Val &v, uint32_t rep) {
858     EXPECT_TRUE(v.is_resource());
859     const ResourceAny &f = v.get_resource();
860     EXPECT_EQ(f.type(), ResourceType(RESOURCE_TYPE));
861     ResourceHost r = f.to_host(cx).unwrap();
862     EXPECT_EQ(r.rep(), rep);
863     EXPECT_EQ(r.type(), RESOURCE_TYPE);
864   };
865 
866   static const auto make = [](Store::Context cx, uint32_t rep) -> Val {
867     return ResourceHost(true, rep, RESOURCE_TYPE).to_any(cx).unwrap();
868   };
869 
870   Engine engine;
871   Linker linker(engine);
872   {
873     LinkerInstance i = linker.root();
874 
875     i.add_resource(
876          "r", ResourceType(RESOURCE_TYPE),
877          +[](Store::Context, uint32_t rep) -> Result<std::monostate> {
878            EXPECT_EQ(rep, 42);
879            return std::monostate();
880          })
881         .unwrap();
882 
883     i.add_func(
884          "f",
885          +[](Store::Context cx, const FuncType &_ty, Span<const Val> args,
886              Span<Val> rets) -> Result<std::monostate> {
887            EXPECT_EQ(args.size(), 1);
888            check(cx, args[0], 42);
889 
890            EXPECT_EQ(rets.size(), 1);
891            rets[0] = make(cx, 43);
892            return std::monostate();
893          })
894         .unwrap();
895   }
896 
897   auto ctx = Context::New(engine,
898                           R"(
899 (component
900   (import "r" (type $r (sub resource)))
901   (import "f" (func $f (param "a" (own $r)) (result (own $r))))
902   (core func $f (canon lower (func $f)))
903 
904   (core module $m
905     (import "" "f" (func $f (param i32) (result i32)))
906 
907     (func (export "call") (param i32) (result i32)
908       local.get 0
909       call $f)
910   )
911 
912   (core instance $m (instantiate $m
913     (with "" (instance
914       (export "f" (func $f))
915     ))
916   ))
917 
918   (func (export "call") (param "a" (own $r)) (result (own $r))
919     (canon lift (core func $m "call")))
920 )
921 )",
922                           linker);
923 
924   auto arg = make(ctx.context, 42);
925   auto res = Val(false);
926 
927   ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))
928       .unwrap();
929   ctx.func.post_return(ctx.context).unwrap();
930 
931   check(ctx.context, res, 43);
932 }
933 
TEST(component,value_guest_resource)934 TEST(component, value_guest_resource) {
935   Engine engine;
936   Linker linker(engine);
937   Store store(engine);
938 
939   Component c = Component::compile(engine,
940                                    R"(
941 (component
942   (core module $a
943     (global $g (mut i32) (i32.const 0))
944 
945     (func (export "dtor") (param i32) (global.set $g (local.get 0)))
946     (func (export "last-dtor-rep") (result i32) global.get $g)
947   )
948   (core instance $a (instantiate $a))
949   (type $r' (resource (rep i32) (dtor (func $a "dtor"))))
950   (export $r "r" (type $r'))
951 
952   (core func $new (canon resource.new $r))
953   (core func $drop (canon resource.drop $r))
954 
955   (core module $b
956     (import "" "new" (func $new (param i32) (result i32)))
957     (import "" "drop" (func $drop (param i32)))
958 
959     (func (export "new") (param i32) (result i32)
960       local.get 0
961       call $new)
962 
963     (func (export "rep") (param i32) (result i32)
964       local.get 0)
965 
966     (func (export "drop") (param i32)
967       local.get 0
968       call $drop)
969   )
970   (core instance $b (instantiate $b
971     (with "" (instance
972       (export "new" (func $new))
973       (export "drop" (func $drop))
974     ))
975   ))
976 
977   (func (export "new") (param "x" u32) (result (own $r))
978     (canon lift (core func $b "new")))
979   (func (export "rep") (param "x" (borrow $r)) (result u32)
980     (canon lift (core func $b "rep")))
981   (func (export "drop") (param "x" (own $r))
982     (canon lift (core func $b "drop")))
983   (func (export "last-dtor-rep") (result u32)
984     (canon lift (core func $a "last-dtor-rep")))
985 
986 )
987 )")
988                     .unwrap();
989 
990   auto instance = linker.instantiate(store, c).unwrap();
991   auto new_index = *instance.get_export_index(store, nullptr, "new");
992   auto rep_index = *instance.get_export_index(store, nullptr, "rep");
993   auto drop_index = *instance.get_export_index(store, nullptr, "drop");
994   auto last_dtor_rep_index =
995       *instance.get_export_index(store, nullptr, "last-dtor-rep");
996   auto new_func = *instance.get_func(store, new_index);
997   auto rep_func = *instance.get_func(store, rep_index);
998   auto drop_func = *instance.get_func(store, drop_index);
999   auto last_dtor_rep_func = *instance.get_func(store, last_dtor_rep_index);
1000 
1001   auto arg1 = Val(uint32_t(100));
1002   auto res1 = Val(false);
1003   new_func.call(store, Span<const Val>(&arg1, 1), Span<Val>(&res1, 1)).unwrap();
1004   new_func.post_return(store).unwrap();
1005 
1006   auto arg2 = Val(uint32_t(101));
1007   auto res2 = Val(false);
1008   new_func.call(store, Span<const Val>(&arg2, 1), Span<Val>(&res2, 1)).unwrap();
1009   new_func.post_return(store).unwrap();
1010 
1011   {
1012     EXPECT_TRUE(res1.is_resource());
1013     EXPECT_TRUE(res2.is_resource());
1014     const auto &resource1 = res1.get_resource();
1015     const auto &resource2 = res2.get_resource();
1016     EXPECT_NE(resource1.type(), ResourceType(100));
1017     EXPECT_NE(resource2.type(), ResourceType(100));
1018     EXPECT_EQ(resource1.type(), resource2.type());
1019     EXPECT_FALSE(resource1.to_host(store));
1020     EXPECT_FALSE(resource2.to_host(store));
1021     EXPECT_TRUE(resource1.owned());
1022     EXPECT_TRUE(resource2.owned());
1023     arg1 = resource1;
1024     arg2 = resource2;
1025   }
1026 
1027   rep_func.call(store, Span<const Val>(&arg1, 1), Span<Val>(&res1, 1)).unwrap();
1028   rep_func.post_return(store).unwrap();
1029   rep_func.call(store, Span<const Val>(&arg2, 1), Span<Val>(&res2, 1)).unwrap();
1030   rep_func.post_return(store).unwrap();
1031 
1032   EXPECT_TRUE(res1.is_u32());
1033   EXPECT_TRUE(res2.is_u32());
1034   EXPECT_EQ(res1.get_u32(), 100);
1035   EXPECT_EQ(res2.get_u32(), 101);
1036 
1037   Val last_rep(false);
1038   last_dtor_rep_func.call(store, Span<const Val>(), Span<Val>(&last_rep, 1))
1039       .unwrap();
1040   last_dtor_rep_func.post_return(store).unwrap();
1041   EXPECT_EQ(last_rep.get_u32(), 0);
1042 
1043   drop_func.call(store, Span<const Val>(&arg1, 1), Span<Val>()).unwrap();
1044   drop_func.post_return(store).unwrap();
1045 
1046   last_dtor_rep_func.call(store, Span<const Val>(), Span<Val>(&last_rep, 1))
1047       .unwrap();
1048   last_dtor_rep_func.post_return(store).unwrap();
1049   EXPECT_EQ(last_rep.get_u32(), 100);
1050 
1051   arg2.get_resource().drop(store).unwrap();
1052 
1053   last_dtor_rep_func.call(store, Span<const Val>(), Span<Val>(&last_rep, 1))
1054       .unwrap();
1055   last_dtor_rep_func.post_return(store).unwrap();
1056   EXPECT_EQ(last_rep.get_u32(), 101);
1057 }
1058 
TEST(component,resources)1059 TEST(component, resources) {
1060   ResourceHost r1(true, 1, 2);
1061   EXPECT_TRUE(r1.owned());
1062   EXPECT_EQ(r1.rep(), 1);
1063   EXPECT_EQ(r1.type(), 2);
1064 
1065   ResourceHost r2 = r1;
1066   EXPECT_TRUE(r1.owned());
1067   EXPECT_EQ(r1.rep(), 1);
1068   EXPECT_EQ(r1.type(), 2);
1069   EXPECT_TRUE(r2.owned());
1070   EXPECT_EQ(r2.rep(), 1);
1071   EXPECT_EQ(r2.type(), 2);
1072 
1073   Engine engine;
1074   Store store(engine);
1075   ResourceAny r3 = r2.to_any(store).unwrap();
1076   EXPECT_TRUE(r3.owned());
1077   ResourceType t3 = r3.type();
1078   EXPECT_EQ(t3, ResourceType(2));
1079 
1080   ResourceHost r4 = r3.to_host(store).unwrap();
1081   EXPECT_TRUE(r4.owned());
1082   EXPECT_EQ(r4.rep(), 1);
1083   EXPECT_EQ(r4.type(), 2);
1084 
1085   EXPECT_FALSE(r3.drop(store));
1086   EXPECT_TRUE(r4.to_any(store).unwrap().drop(store));
1087 
1088   Val v = r4.to_any(store).unwrap();
1089   EXPECT_TRUE(v.is_resource());
1090   const ResourceAny &r5 = v.get_resource();
1091   EXPECT_TRUE(r5.owned());
1092   EXPECT_EQ(r5.type(), ResourceType(2));
1093 }
1094