Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/c-api/tests/component/values.cc
3052 views
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
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
69
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1095