Path: blob/main/crates/c-api/tests/component/values.cc
3052 views
#include "utils.h"12#include <gtest/gtest.h>3#include <wasmtime.h>4#include <wasmtime/component.hh>5#include <wasmtime/store.hh>67#include <array>8#include <format>9#include <optional>10#include <span>11#include <variant>1213using namespace wasmtime::component;14using wasmtime::Engine;15using wasmtime::Result;16using wasmtime::Span;17using wasmtime::Store;1819static std::string echo_component(std::string_view type, std::string_view func,20std::string_view host_params) {21return std::format(22R"END(23(component24(type $Foo' {})25(import "foo" (type $Foo (eq $Foo')))26(import "do" (func $do (param "a" $Foo) (result $Foo)))27(core module $libc28(memory (export "memory") 1)29{}30)31(core instance $libc (instantiate $libc))32(core func $do_lower (canon lower (func $do) (memory $libc "memory") (realloc (func $libc "realloc"))))3334(core module $doer35(import "host" "do" (func $do {}))36(import "libc" "memory" (memory 1))37(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))3839(func (export "call")40{})41)42(core instance $doer (instantiate $doer43(with "host" (instance (export "do" (func $do_lower))))44(with "libc" (instance $libc))45))4647(func $call48(param "a" $Foo)49(result $Foo)50(canon lift51(core func $doer "call")52(memory $libc "memory")53(realloc (func $libc "realloc")))54)5556(export "call" (func $call))57)58)END",59type, REALLOC_AND_FREE, host_params, func);60}6162struct Context {63Store store;64Store::Context context;65Instance instance;66Func func;6768static Context New(Engine &engine, std::string_view component_text,69Linker &linker) {70Store store(engine);71const auto context = store.context();72Component component = Component::compile(engine, component_text).unwrap();7374auto f = component.export_index(nullptr, "call");7576EXPECT_TRUE(f);7778auto instance = linker.instantiate(context, component).unwrap();79auto func = *instance.get_func(context, *f);8081return Context{82.store = std::move(store),83.context = context,84.instance = instance,85.func = func,86};87}88};8990typedef Result<std::monostate> (*host_func_t)(Store::Context, const FuncType &,91Span<const Val>, Span<Val>);9293static Context create(std::string_view type, std::string_view body,94std::string_view host_params, host_func_t callback) {95Engine engine;96Linker linker(engine);97linker.root().add_func("do", callback).unwrap();98auto component_text = echo_component(type, body, host_params);99return Context::New(engine, component_text, linker);100}101102TEST(component, value_record) {103static const auto check = [](const Val &v, uint64_t x, uint64_t y) {104EXPECT_TRUE(v.is_record());105const Record &r = v.get_record();106EXPECT_EQ(r.size(), 2);107108const auto &x_field = *r.begin();109EXPECT_EQ(x_field.name(), "x");110const auto &x_field_val = x_field.value();111EXPECT_TRUE(x_field_val.is_u64());112EXPECT_EQ(x_field_val.get_u64(), x);113114const auto &y_field = *(r.begin() + 1);115EXPECT_EQ(y_field.name(), "y");116const auto &y_field_val = y_field.value();117EXPECT_TRUE(y_field_val.is_u64());118EXPECT_EQ(y_field_val.get_u64(), y);119};120121static const auto make = [](uint64_t x, uint64_t y) -> Val {122return Record({123{"x", x},124{"y", y},125});126};127128auto ctx = create(129R"((record (field "x" u64) (field "y" u64)))", R"(130(param $x i64)131(param $y i64)132(result i32)133(local $res i32)134local.get $x135local.get $y136(call $realloc137(i32.const 0)138(i32.const 0)139(i32.const 4)140(i32.const 16))141local.tee $res142call $do143local.get $res144)",145"(param i64 i64 i32)",146+[](Store::Context, const FuncType &_ty, Span<const Val> args,147Span<Val> rets) -> Result<std::monostate> {148EXPECT_EQ(args.size(), 1);149check(args[0], 1, 2);150151EXPECT_EQ(rets.size(), 1);152rets[0] = make(3, 4);153154return std::monostate();155});156157auto arg = make(1, 2);158auto res = Val(false);159160ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))161.unwrap();162ctx.func.post_return(ctx.context).unwrap();163164check(res, 3, 4);165}166167TEST(component, value_string) {168static const auto check = [](const Val &v, std::string_view text) {169EXPECT_TRUE(v.is_string());170EXPECT_EQ(v.get_string(), text);171};172173static const auto make = [](std::string_view text) -> Val {174return Val::string(text);175};176177auto ctx = create(178R"(string)", R"(179(param $x i32)180(param $y i32)181(result i32)182(local $res i32)183local.get $x184local.get $y185(call $realloc186(i32.const 0)187(i32.const 0)188(i32.const 4)189(i32.const 8))190local.tee $res191call $do192local.get $res193)",194"(param i32 i32 i32)",195+[](Store::Context, const FuncType &, Span<const Val> args,196Span<Val> rets) -> Result<std::monostate> {197EXPECT_EQ(args.size(), 1);198check(args[0], "hello from A!");199200EXPECT_EQ(rets.size(), 1);201rets[0] = make("hello from B!");202203return std::monostate();204});205206auto arg = make("hello from A!");207auto res = Val(false);208209ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))210.unwrap();211ctx.func.post_return(ctx.context).unwrap();212213check(res, "hello from B!");214}215216TEST(component, value_list) {217static const auto check = [](const Val &v, std::vector<uint32_t> data) {218EXPECT_TRUE(v.is_list());219const List &l = v.get_list();220EXPECT_EQ(l.size(), data.size());221222for (auto i = 0; i < data.size(); i++) {223const auto &elem = l.begin()[i];224EXPECT_TRUE(elem.is_u32());225EXPECT_EQ(elem.get_u32(), data[i]);226}227};228229static const auto make = [](std::vector<Val> data) -> Val {230return List(data);231};232233auto ctx = create(234R"((list u32))", R"(235(param $x i32)236(param $y i32)237(result i32)238(local $res i32)239local.get $x240local.get $y241(call $realloc242(i32.const 0)243(i32.const 0)244(i32.const 4)245(i32.const 8))246local.tee $res247call $do248local.get $res249)",250"(param i32 i32 i32)",251+[](Store::Context, const FuncType &, Span<const Val> args,252Span<Val> rets) -> Result<std::monostate> {253EXPECT_EQ(args.size(), 1);254check(args[0], {1, 2, 3});255256EXPECT_EQ(rets.size(), 1);257rets[0] = make({uint32_t(4), uint32_t(5), uint32_t(6), uint32_t(7)});258259return std::monostate();260});261262auto arg = make({uint32_t(1), uint32_t(2), uint32_t(3)});263auto res = Val(false);264265ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))266.unwrap();267ctx.func.post_return(ctx.context).unwrap();268269check(res, {4, 5, 6, 7});270}271272TEST(component, value_tuple) {273static const auto check = [](const Val &v, std::vector<uint32_t> data) {274EXPECT_TRUE(v.is_tuple());275const Tuple &t = v.get_tuple();276EXPECT_EQ(t.size(), data.size());277for (auto i = 0; i < data.size(); i++) {278const auto &elem = t.begin()[i];279EXPECT_TRUE(elem.is_u32());280EXPECT_EQ(elem.get_u32(), data[i]);281}282};283284static const auto make = [](std::vector<Val> data) -> Val {285return Tuple(data);286};287288auto ctx = create(289R"((tuple u32 u32 u32))", R"(290(param $x i32)291(param $y i32)292(param $z i32)293(result i32)294(local $res i32)295local.get $x296local.get $y297local.get $z298(call $realloc299(i32.const 0)300(i32.const 0)301(i32.const 4)302(i32.const 12))303local.tee $res304call $do305local.get $res306)",307"(param i32 i32 i32 i32)",308+[](Store::Context, const FuncType &, Span<const Val> args,309Span<Val> rets) -> Result<std::monostate> {310EXPECT_EQ(args.size(), 1);311check(args[0], {1, 2, 3});312313EXPECT_EQ(rets.size(), 1);314rets[0] = make({uint32_t(4), uint32_t(5), uint32_t(6)});315316return std::monostate();317});318319auto arg = make({uint32_t(1), uint32_t(2), uint32_t(3)});320auto res = Val(false);321322ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))323.unwrap();324ctx.func.post_return(ctx.context).unwrap();325326check(res, {4, 5, 6});327}328329TEST(component, value_variant) {330static const auto check_aa = [](const Val &v, uint32_t value) {331EXPECT_TRUE(v.is_variant());332const Variant &var = v.get_variant();333EXPECT_EQ(var.discriminant(), "aa");334EXPECT_NE(var.value(), nullptr);335EXPECT_TRUE(var.value()->is_u32());336EXPECT_EQ(var.value()->get_u32(), value);337};338339static const auto check_bb = [](const Val &v, std::string_view value) {340EXPECT_TRUE(v.is_variant());341const Variant &var = v.get_variant();342EXPECT_EQ(var.discriminant(), "bb");343EXPECT_NE(var.value(), nullptr);344EXPECT_TRUE(var.value()->is_string());345EXPECT_EQ(var.value()->get_string(), value);346};347348static const auto make_aa = [](uint32_t value) -> Val {349return Variant("aa", Val(value));350};351352static const auto make_bb = [](std::string_view value) -> Val {353return Variant("bb", Val::string(value));354};355356auto ctx = create(357R"(358(variant359(case "aa" u32)360(case "bb" string)361)362)",363R"(364(param $x i32)365(param $y i32)366(param $z i32)367(result i32)368(local $res i32)369local.get $x370local.get $y371local.get $z372(call $realloc373(i32.const 0)374(i32.const 0)375(i32.const 4)376(i32.const 12))377local.tee $res378call $do379local.get $res380)",381"(param i32 i32 i32 i32)",382+[](Store::Context, const FuncType &, Span<const Val> args,383Span<Val> rets) -> Result<std::monostate> {384EXPECT_EQ(args.size(), 1);385check_aa(args[0], 123);386387EXPECT_EQ(rets.size(), 1);388rets[0] = make_bb("textt");389390return std::monostate();391});392393auto arg = make_aa(123);394auto res = Val(false);395396ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))397.unwrap();398ctx.func.post_return(ctx.context).unwrap();399400check_bb(res, "textt");401}402403TEST(component, value_enum) {404static const auto check = [](const Val &v, std::string_view text) {405EXPECT_TRUE(v.is_enum());406EXPECT_EQ(v.get_enum(), text);407};408409static const auto make = [](std::string_view text) -> Val {410return Val::enum_(text);411};412413auto ctx = create(414R"((enum "aa" "bb"))", R"(415(param $x i32)416(result i32)417local.get $x418call $do419)",420"(param i32) (result i32)",421+[](Store::Context, const FuncType &, Span<const Val> args,422Span<Val> rets) -> Result<std::monostate> {423EXPECT_EQ(args.size(), 1);424check(args[0], "aa");425426EXPECT_EQ(rets.size(), 1);427rets[0] = make("bb");428429return std::monostate();430});431432auto arg = make("aa");433auto res = Val(false);434435ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))436.unwrap();437ctx.func.post_return(ctx.context).unwrap();438439check(res, "bb");440}441442TEST(component, value_option) {443static const auto check = [](const Val &v, std::optional<uint32_t> value) {444EXPECT_TRUE(v.is_option());445const WitOption &o = v.get_option();446if (value.has_value()) {447EXPECT_NE(o.value(), nullptr);448EXPECT_TRUE(o.value()->is_u32());449EXPECT_EQ(o.value()->get_u32(), *value);450} else {451EXPECT_EQ(o.value(), nullptr);452}453};454455static const auto make = [](std::optional<uint32_t> value) -> Val {456if (value) {457return WitOption(Val(*value));458}459return WitOption(std::nullopt);460};461462auto ctx = create(463R"((option u32))", R"(464(param $x i32)465(param $y i32)466(result i32)467(local $res i32)468local.get $x469local.get $y470(call $realloc471(i32.const 0)472(i32.const 0)473(i32.const 4)474(i32.const 8))475local.tee $res476call $do477local.get $res478)",479"(param i32 i32 i32)",480+[](Store::Context, const FuncType &, Span<const Val> args,481Span<Val> rets) -> Result<std::monostate> {482EXPECT_EQ(args.size(), 1);483check(args[0], 123);484485EXPECT_EQ(rets.size(), 1);486rets[0] = make({});487488return std::monostate();489});490491auto arg = make(123);492auto res = Val(false);493494ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))495.unwrap();496ctx.func.post_return(ctx.context).unwrap();497498check(res, {});499}500501TEST(component, value_result) {502static const auto check = [](const Val &v, bool expected_is_ok,503uint32_t expected_value) {504EXPECT_TRUE(v.is_result());505const WitResult &r = v.get_result();506EXPECT_EQ(r.is_ok(), expected_is_ok);507EXPECT_NE(r.payload(), nullptr);508EXPECT_TRUE(r.payload()->is_u32());509EXPECT_EQ(r.payload()->get_u32(), expected_value);510};511512static const auto make = [](bool is_ok, uint32_t value) -> Val {513if (is_ok) {514return WitResult::ok(Val(value));515}516return WitResult::err(Val(value));517};518519auto ctx = create(520R"((result u32 (error u32)))", R"(521(param $x i32)522(param $y i32)523(result i32)524(local $res i32)525local.get $x526local.get $y527(call $realloc528(i32.const 0)529(i32.const 0)530(i32.const 4)531(i32.const 8))532local.tee $res533call $do534local.get $res535)",536"(param i32 i32 i32)",537+[](Store::Context, const FuncType &, Span<const Val> args,538Span<Val> rets) -> Result<std::monostate> {539EXPECT_EQ(args.size(), 1);540check(args[0], true, 123);541542EXPECT_EQ(rets.size(), 1);543rets[0] = make(false, 456);544545return std::monostate();546});547548auto arg = make(true, 123);549auto res = Val(false);550551ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))552.unwrap();553ctx.func.post_return(ctx.context).unwrap();554555check(res, false, 456);556}557558TEST(component, value_flags) {559static const auto check = [](const Val &v, std::vector<std::string> data) {560EXPECT_TRUE(v.is_flags());561const Flags &f = v.get_flags();562563EXPECT_EQ(f.size(), data.size());564for (auto i = 0; i < data.size(); i++) {565EXPECT_EQ(f.begin()[i].name(), data[i]);566}567};568569static const auto make = [](std::vector<Flag> data) -> Val {570return Flags(data);571};572573auto ctx = create(574R"((flags "aa" "bb"))", R"(575(param $x i32)576(result i32)577local.get $x578call $do579)",580"(param i32) (result i32)",581+[](Store::Context, const FuncType &, Span<const Val> args,582Span<Val> rets) -> Result<std::monostate> {583EXPECT_EQ(args.size(), 1);584check(args[0], {"aa"});585586EXPECT_EQ(rets.size(), 1);587rets[0] = make({Flag("aa"), Flag("bb")});588589return std::monostate();590});591592auto arg = make({Flag("aa")});593auto res = Val(false);594595ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))596.unwrap();597ctx.func.post_return(ctx.context).unwrap();598599check(res, {"aa", "bb"});600}601602TEST(component, value_list_inner) {603auto x = wasmtime_component_val_t{604.kind = WASMTIME_COMPONENT_LIST,605};606wasmtime_component_vallist_new_empty(&x.of.list);607EXPECT_EQ(x.of.list.data, nullptr);608EXPECT_EQ(x.of.list.size, 0);609610wasmtime_component_vallist_new_uninit(&x.of.list, 1);611EXPECT_NE(x.of.list.data, nullptr);612EXPECT_EQ(x.of.list.size, 1);613614wasmtime_component_vallist_delete(&x.of.list);615616auto items = std::array{617wasmtime_component_val_t{618.kind = WASMTIME_COMPONENT_U32,619.of = {.u32 = 123},620},621};622623wasmtime_component_vallist_new(&x.of.list, items.size(), items.data());624EXPECT_NE(x.of.list.data, nullptr);625EXPECT_EQ(x.of.list.size, 1);626627EXPECT_EQ(x.of.list.data[0].kind, WASMTIME_COMPONENT_U32);628EXPECT_EQ(x.of.list.data[0].of.u32, 123);629630auto clone = wasmtime_component_val_t{631.kind = WASMTIME_COMPONENT_LIST,632};633634wasmtime_component_vallist_copy(&clone.of.list, &x.of.list);635wasmtime_component_vallist_delete(&x.of.list);636637EXPECT_NE(clone.of.list.data, nullptr);638EXPECT_EQ(clone.of.list.size, 1);639640EXPECT_EQ(clone.of.list.data[0].kind, WASMTIME_COMPONENT_U32);641EXPECT_EQ(clone.of.list.data[0].of.u32, 123);642643wasmtime_component_vallist_delete(&clone.of.list);644}645646TEST(component, records) {647Record r({{"x", uint64_t(1)}, {"y", uint64_t(2)}});648EXPECT_EQ(r.size(), 2);649650for (auto &field : r) {651if (field.name() == "x") {652EXPECT_EQ(field.value().get_u64(), 1);653} else if (field.name() == "y") {654EXPECT_EQ(field.value().get_u64(), 2);655} else {656FAIL() << "unexpected field name: " << field.name();657}658}659660Record r2({{"x", r}, {"y", uint64_t(2)}});661EXPECT_EQ(r2.size(), 2);662EXPECT_EQ(r.size(), 2);663664for (auto &field : r2) {665if (field.name() == "x") {666auto inner = field.value().get_record();667EXPECT_EQ(inner.size(), 2);668for (auto &inner_field : inner) {669if (inner_field.name() == "x") {670EXPECT_EQ(inner_field.value().get_u64(), 1);671} else if (inner_field.name() == "y") {672EXPECT_EQ(inner_field.value().get_u64(), 2);673} else {674FAIL() << "unexpected inner field name: " << inner_field.name();675}676}677} else if (field.name() == "y") {678EXPECT_EQ(field.value().get_u64(), 2);679} else {680FAIL() << "unexpected field name: " << field.name();681}682}683684Val record = r2;685EXPECT_TRUE(record.is_record());686EXPECT_EQ(r2.size(), 2);687Val record2 = std::move(r2);688EXPECT_TRUE(record2.is_record());689EXPECT_EQ(r2.size(), 0);690}691692TEST(component, lists) {693List l({uint32_t(1), uint32_t(2), uint32_t(3)});694EXPECT_EQ(l.size(), 3);695uint32_t expected = 1;696for (auto &val : l) {697EXPECT_EQ(val.get_u32(), expected);698expected++;699}700701List l2 = l;702EXPECT_EQ(l.size(), 3);703EXPECT_EQ(l2.size(), 3);704705List l3 = std::move(l);706EXPECT_EQ(l.size(), 0);707EXPECT_EQ(l3.size(), 3);708709Val value(l3);710value.get_list();711}712713TEST(component, tuples) {714Tuple l({uint32_t(1), uint64_t(2), uint8_t(3)});715EXPECT_EQ(l.size(), 3);716717Val value(l);718EXPECT_TRUE(value.is_tuple());719EXPECT_EQ(l.size(), 3);720721for (auto &val : l) {722if (val.is_u32()) {723EXPECT_EQ(val.get_u32(), 1);724} else if (val.is_u64()) {725EXPECT_EQ(val.get_u64(), 2);726} else if (val.is_u8()) {727EXPECT_EQ(val.get_u8(), 3);728} else {729FAIL() << "unexpected tuple value type";730}731}732}733734TEST(component, variants) {735Variant v("hello", uint32_t(42));736EXPECT_EQ(v.discriminant(), "hello");737EXPECT_TRUE(v.value()->is_u32());738EXPECT_EQ(v.value()->get_u32(), 42);739740Variant v2("another", v);741EXPECT_EQ(v.discriminant(), "hello");742EXPECT_TRUE(v.value()->is_u32());743EXPECT_EQ(v.value()->get_u32(), 42);744EXPECT_EQ(v2.discriminant(), "another");745EXPECT_TRUE(v2.value()->is_variant());746auto inner = v2.value()->get_variant();747EXPECT_EQ(inner.discriminant(), "hello");748EXPECT_TRUE(inner.value()->is_u32());749EXPECT_EQ(inner.value()->get_u32(), 42);750751Val value = v;752EXPECT_TRUE(value.is_variant());753auto v3 = value.get_variant();754EXPECT_EQ(v3.discriminant(), "hello");755EXPECT_TRUE(v3.value()->is_u32());756EXPECT_EQ(v3.value()->get_u32(), 42);757}758759TEST(component, strings) {760Val v = Val::string("hi");761EXPECT_TRUE(v.is_string());762EXPECT_EQ(v.get_string(), "hi");763764v = Val::string("another");765EXPECT_TRUE(v.is_string());766EXPECT_EQ(v.get_string(), "another");767}768769TEST(component, results) {770WitResult r = WitResult::ok(uint32_t(42));771EXPECT_TRUE(r.is_ok());772EXPECT_EQ(r.payload()->get_u32(), 42);773774r = WitResult::ok(std::nullopt);775EXPECT_TRUE(r.is_ok());776EXPECT_EQ(r.payload(), nullptr);777778r = WitResult::err(std::nullopt);779EXPECT_FALSE(r.is_ok());780EXPECT_EQ(r.payload(), nullptr);781782Val v = r;783EXPECT_TRUE(v.is_result());784auto r2 = v.get_result();785EXPECT_FALSE(r2.is_ok());786EXPECT_EQ(r2.payload(), nullptr);787788r = WitResult::ok(uint32_t(99));789v = r;790EXPECT_TRUE(r.is_ok());791EXPECT_NE(r.payload(), nullptr);792EXPECT_EQ(r.payload()->get_u32(), 99);793}794795TEST(component, enums) {796Val v = Val::enum_("hi");797EXPECT_TRUE(v.is_enum());798EXPECT_EQ(v.get_enum(), "hi");799800v = Val::enum_("another");801EXPECT_TRUE(v.is_enum());802EXPECT_EQ(v.get_enum(), "another");803}804805TEST(component, options) {806WitOption o(Val(uint32_t(42)));807EXPECT_NE(o.value(), nullptr);808EXPECT_TRUE(o.value()->is_u32());809EXPECT_EQ(o.value()->get_u32(), 42);810811Val v(o);812WitOption o2(v);813EXPECT_NE(o.value(), nullptr);814EXPECT_TRUE(o2.value()->is_option());815auto inner = o2.value()->get_option();816auto value = inner.value();817EXPECT_NE(value, nullptr);818EXPECT_TRUE(value->is_u32());819EXPECT_EQ(value->get_u32(), 42);820821EXPECT_NE(o.value(), nullptr);822EXPECT_TRUE(o.value()->is_u32());823EXPECT_EQ(o.value()->get_u32(), 42);824825WitOption o3(std::nullopt);826EXPECT_EQ(o3.value(), nullptr);827}828829TEST(component, flags) {830std::vector<Flag> flags = {831Flag("a"),832Flag("b"),833Flag("c"),834};835Flags f(flags);836EXPECT_EQ(f.size(), 3);837for (auto i = 0; i < f.size(); i++) {838EXPECT_EQ(f.begin()[i].name(), flags[i].name());839}840841flags.clear();842Flags f2(flags);843EXPECT_EQ(f2.size(), 0);844EXPECT_EQ(f.size(), 3);845846Val v = f;847EXPECT_TRUE(v.is_flags());848Flags f3 = v.get_flags();849EXPECT_EQ(f3.size(), 3);850EXPECT_EQ(f.size(), 3);851}852853TEST(component, value_host_resource) {854static const uint32_t RESOURCE_TYPE = 100;855856static const auto check = [](Store::Context cx, const Val &v, uint32_t rep) {857EXPECT_TRUE(v.is_resource());858const ResourceAny &f = v.get_resource();859EXPECT_EQ(f.type(), ResourceType(RESOURCE_TYPE));860ResourceHost r = f.to_host(cx).unwrap();861EXPECT_EQ(r.rep(), rep);862EXPECT_EQ(r.type(), RESOURCE_TYPE);863};864865static const auto make = [](Store::Context cx, uint32_t rep) -> Val {866return ResourceHost(true, rep, RESOURCE_TYPE).to_any(cx).unwrap();867};868869Engine engine;870Linker linker(engine);871{872LinkerInstance i = linker.root();873874i.add_resource(875"r", ResourceType(RESOURCE_TYPE),876+[](Store::Context, uint32_t rep) -> Result<std::monostate> {877EXPECT_EQ(rep, 42);878return std::monostate();879})880.unwrap();881882i.add_func(883"f",884+[](Store::Context cx, const FuncType &_ty, Span<const Val> args,885Span<Val> rets) -> Result<std::monostate> {886EXPECT_EQ(args.size(), 1);887check(cx, args[0], 42);888889EXPECT_EQ(rets.size(), 1);890rets[0] = make(cx, 43);891return std::monostate();892})893.unwrap();894}895896auto ctx = Context::New(engine,897R"(898(component899(import "r" (type $r (sub resource)))900(import "f" (func $f (param "a" (own $r)) (result (own $r))))901(core func $f (canon lower (func $f)))902903(core module $m904(import "" "f" (func $f (param i32) (result i32)))905906(func (export "call") (param i32) (result i32)907local.get 0908call $f)909)910911(core instance $m (instantiate $m912(with "" (instance913(export "f" (func $f))914))915))916917(func (export "call") (param "a" (own $r)) (result (own $r))918(canon lift (core func $m "call")))919)920)",921linker);922923auto arg = make(ctx.context, 42);924auto res = Val(false);925926ctx.func.call(ctx.context, Span<const Val>(&arg, 1), Span<Val>(&res, 1))927.unwrap();928ctx.func.post_return(ctx.context).unwrap();929930check(ctx.context, res, 43);931}932933TEST(component, value_guest_resource) {934Engine engine;935Linker linker(engine);936Store store(engine);937938Component c = Component::compile(engine,939R"(940(component941(core module $a942(global $g (mut i32) (i32.const 0))943944(func (export "dtor") (param i32) (global.set $g (local.get 0)))945(func (export "last-dtor-rep") (result i32) global.get $g)946)947(core instance $a (instantiate $a))948(type $r' (resource (rep i32) (dtor (func $a "dtor"))))949(export $r "r" (type $r'))950951(core func $new (canon resource.new $r))952(core func $drop (canon resource.drop $r))953954(core module $b955(import "" "new" (func $new (param i32) (result i32)))956(import "" "drop" (func $drop (param i32)))957958(func (export "new") (param i32) (result i32)959local.get 0960call $new)961962(func (export "rep") (param i32) (result i32)963local.get 0)964965(func (export "drop") (param i32)966local.get 0967call $drop)968)969(core instance $b (instantiate $b970(with "" (instance971(export "new" (func $new))972(export "drop" (func $drop))973))974))975976(func (export "new") (param "x" u32) (result (own $r))977(canon lift (core func $b "new")))978(func (export "rep") (param "x" (borrow $r)) (result u32)979(canon lift (core func $b "rep")))980(func (export "drop") (param "x" (own $r))981(canon lift (core func $b "drop")))982(func (export "last-dtor-rep") (result u32)983(canon lift (core func $a "last-dtor-rep")))984985)986)")987.unwrap();988989auto instance = linker.instantiate(store, c).unwrap();990auto new_index = *instance.get_export_index(store, nullptr, "new");991auto rep_index = *instance.get_export_index(store, nullptr, "rep");992auto drop_index = *instance.get_export_index(store, nullptr, "drop");993auto last_dtor_rep_index =994*instance.get_export_index(store, nullptr, "last-dtor-rep");995auto new_func = *instance.get_func(store, new_index);996auto rep_func = *instance.get_func(store, rep_index);997auto drop_func = *instance.get_func(store, drop_index);998auto last_dtor_rep_func = *instance.get_func(store, last_dtor_rep_index);9991000auto arg1 = Val(uint32_t(100));1001auto res1 = Val(false);1002new_func.call(store, Span<const Val>(&arg1, 1), Span<Val>(&res1, 1)).unwrap();1003new_func.post_return(store).unwrap();10041005auto arg2 = Val(uint32_t(101));1006auto res2 = Val(false);1007new_func.call(store, Span<const Val>(&arg2, 1), Span<Val>(&res2, 1)).unwrap();1008new_func.post_return(store).unwrap();10091010{1011EXPECT_TRUE(res1.is_resource());1012EXPECT_TRUE(res2.is_resource());1013const auto &resource1 = res1.get_resource();1014const auto &resource2 = res2.get_resource();1015EXPECT_NE(resource1.type(), ResourceType(100));1016EXPECT_NE(resource2.type(), ResourceType(100));1017EXPECT_EQ(resource1.type(), resource2.type());1018EXPECT_FALSE(resource1.to_host(store));1019EXPECT_FALSE(resource2.to_host(store));1020EXPECT_TRUE(resource1.owned());1021EXPECT_TRUE(resource2.owned());1022arg1 = resource1;1023arg2 = resource2;1024}10251026rep_func.call(store, Span<const Val>(&arg1, 1), Span<Val>(&res1, 1)).unwrap();1027rep_func.post_return(store).unwrap();1028rep_func.call(store, Span<const Val>(&arg2, 1), Span<Val>(&res2, 1)).unwrap();1029rep_func.post_return(store).unwrap();10301031EXPECT_TRUE(res1.is_u32());1032EXPECT_TRUE(res2.is_u32());1033EXPECT_EQ(res1.get_u32(), 100);1034EXPECT_EQ(res2.get_u32(), 101);10351036Val last_rep(false);1037last_dtor_rep_func.call(store, Span<const Val>(), Span<Val>(&last_rep, 1))1038.unwrap();1039last_dtor_rep_func.post_return(store).unwrap();1040EXPECT_EQ(last_rep.get_u32(), 0);10411042drop_func.call(store, Span<const Val>(&arg1, 1), Span<Val>()).unwrap();1043drop_func.post_return(store).unwrap();10441045last_dtor_rep_func.call(store, Span<const Val>(), Span<Val>(&last_rep, 1))1046.unwrap();1047last_dtor_rep_func.post_return(store).unwrap();1048EXPECT_EQ(last_rep.get_u32(), 100);10491050arg2.get_resource().drop(store).unwrap();10511052last_dtor_rep_func.call(store, Span<const Val>(), Span<Val>(&last_rep, 1))1053.unwrap();1054last_dtor_rep_func.post_return(store).unwrap();1055EXPECT_EQ(last_rep.get_u32(), 101);1056}10571058TEST(component, resources) {1059ResourceHost r1(true, 1, 2);1060EXPECT_TRUE(r1.owned());1061EXPECT_EQ(r1.rep(), 1);1062EXPECT_EQ(r1.type(), 2);10631064ResourceHost r2 = r1;1065EXPECT_TRUE(r1.owned());1066EXPECT_EQ(r1.rep(), 1);1067EXPECT_EQ(r1.type(), 2);1068EXPECT_TRUE(r2.owned());1069EXPECT_EQ(r2.rep(), 1);1070EXPECT_EQ(r2.type(), 2);10711072Engine engine;1073Store store(engine);1074ResourceAny r3 = r2.to_any(store).unwrap();1075EXPECT_TRUE(r3.owned());1076ResourceType t3 = r3.type();1077EXPECT_EQ(t3, ResourceType(2));10781079ResourceHost r4 = r3.to_host(store).unwrap();1080EXPECT_TRUE(r4.owned());1081EXPECT_EQ(r4.rep(), 1);1082EXPECT_EQ(r4.type(), 2);10831084EXPECT_FALSE(r3.drop(store));1085EXPECT_TRUE(r4.to_any(store).unwrap().drop(store));10861087Val v = r4.to_any(store).unwrap();1088EXPECT_TRUE(v.is_resource());1089const ResourceAny &r5 = v.get_resource();1090EXPECT_TRUE(r5.owned());1091EXPECT_EQ(r5.type(), ResourceType(2));1092}109310941095