#ifndef WASMTIME_GC_HH
#define WASMTIME_GC_HH
#include <vector>
#include <wasmtime/gc.h>
#include <wasmtime/val.hh>
namespace wasmtime {
class StructRef;
class ArrayRef;
class EqRef {
friend class Val;
friend class AnyRef;
wasmtime_eqref_t val;
public:
explicit EqRef(wasmtime_eqref_t val) : val(val) {}
EqRef(const EqRef &other) { wasmtime_eqref_clone(&other.val, &val); }
EqRef &operator=(const EqRef &other) {
wasmtime_eqref_unroot(&val);
wasmtime_eqref_clone(&other.val, &val);
return *this;
}
EqRef(EqRef &&other) {
val = other.val;
wasmtime_eqref_set_null(&other.val);
}
EqRef &operator=(EqRef &&other) {
wasmtime_eqref_unroot(&val);
val = other.val;
wasmtime_eqref_set_null(&other.val);
return *this;
}
~EqRef() { wasmtime_eqref_unroot(&val); }
static EqRef from_i31(Store::Context cx, uint32_t val) {
wasmtime_eqref_t out;
wasmtime_eqref_from_i31(cx.capi(), val, &out);
return EqRef(out);
}
bool is_i31(Store::Context cx) const {
return wasmtime_eqref_is_i31(cx.capi(), &val);
}
std::optional<uint32_t> i31_get_u(Store::Context cx) const {
uint32_t dst;
if (wasmtime_eqref_i31_get_u(cx.capi(), &val, &dst))
return dst;
return std::nullopt;
}
std::optional<int32_t> i31_get_s(Store::Context cx) const {
int32_t dst;
if (wasmtime_eqref_i31_get_s(cx.capi(), &val, &dst))
return dst;
return std::nullopt;
}
bool is_struct(Store::Context cx) const {
return wasmtime_eqref_is_struct(cx.capi(), &val);
}
bool is_array(Store::Context cx) const {
return wasmtime_eqref_is_array(cx.capi(), &val);
}
AnyRef to_anyref() const {
wasmtime_anyref_t out;
wasmtime_eqref_to_anyref(&val, &out);
return AnyRef(out);
}
inline StructRef as_struct(Store::Context cx) const;
inline ArrayRef as_array(Store::Context cx) const;
};
struct FieldType {
wasmtime_storage_kind_t kind;
bool mutable_;
static FieldType mut_(wasmtime_storage_kind_t k) { return {k, true}; }
static FieldType const_(wasmtime_storage_kind_t k) { return {k, false}; }
};
class StructType {
struct Deleter {
void operator()(wasmtime_struct_type_t *p) const {
wasmtime_struct_type_delete(p);
}
};
std::unique_ptr<wasmtime_struct_type_t, Deleter> ptr;
public:
static StructType create(const Engine &engine,
const std::vector<FieldType> &fields) {
static_assert(sizeof(FieldType) == sizeof(wasmtime_field_type_t));
auto *raw = wasmtime_struct_type_new(
engine.capi(),
reinterpret_cast<const wasmtime_field_type_t *>(fields.data()),
fields.size());
StructType ty;
ty.ptr.reset(raw);
return ty;
}
const wasmtime_struct_type_t *capi() const { return ptr.get(); }
private:
StructType() = default;
friend class StructRefPre;
};
class StructRefPre {
friend class StructRef;
WASMTIME_OWN_WRAPPER(StructRefPre, wasmtime_struct_ref_pre)
public:
static StructRefPre create(Store::Context cx, const StructType &ty) {
auto *raw = wasmtime_struct_ref_pre_new(cx.capi(), ty.capi());
StructRefPre pre(raw);
return pre;
}
};
class StructRef {
friend class EqRef;
friend class Val;
friend class AnyRef;
wasmtime_structref_t val;
public:
explicit StructRef(wasmtime_structref_t val) : val(val) {}
StructRef(const StructRef &other) {
wasmtime_structref_clone(&other.val, &val);
}
StructRef &operator=(const StructRef &other) {
wasmtime_structref_unroot(&val);
wasmtime_structref_clone(&other.val, &val);
return *this;
}
StructRef(StructRef &&other) {
val = other.val;
wasmtime_structref_set_null(&other.val);
}
StructRef &operator=(StructRef &&other) {
wasmtime_structref_unroot(&val);
val = other.val;
wasmtime_structref_set_null(&other.val);
return *this;
}
~StructRef() { wasmtime_structref_unroot(&val); }
static Result<StructRef> create(Store::Context cx, const StructRefPre &pre,
const std::vector<Val> &fields) {
std::vector<wasmtime_val_t> c_fields;
c_fields.reserve(fields.size());
for (auto &f : fields) {
c_fields.push_back(f.val);
}
wasmtime_structref_t out;
auto *err = wasmtime_structref_new(cx.capi(), pre.capi(), c_fields.data(),
c_fields.size(), &out);
if (err)
return Result<StructRef>(Error(err));
return Result<StructRef>(StructRef(out));
}
Result<Val> field(Store::Context cx, size_t index) const {
wasmtime_val_t out;
auto *err = wasmtime_structref_field(cx.capi(), &val, index, &out);
if (err)
return Result<Val>(Error(err));
return Result<Val>(Val(out));
}
Result<std::monostate> set_field(Store::Context cx, size_t index,
const Val &value) const {
auto *err =
wasmtime_structref_set_field(cx.capi(), &val, index, &value.val);
if (err)
return Result<std::monostate>(Error(err));
return Result<std::monostate>(std::monostate{});
}
AnyRef to_anyref() const {
wasmtime_anyref_t out;
wasmtime_structref_to_anyref(&val, &out);
return AnyRef(out);
}
EqRef to_eqref() const {
wasmtime_eqref_t out;
wasmtime_structref_to_eqref(&val, &out);
return EqRef(out);
}
};
inline StructRef EqRef::as_struct(Store::Context cx) const {
wasmtime_structref_t out;
wasmtime_eqref_as_struct(cx.capi(), &val, &out);
return StructRef(out);
}
class ArrayType {
struct Deleter {
void operator()(wasmtime_array_type_t *p) const {
wasmtime_array_type_delete(p);
}
};
std::unique_ptr<wasmtime_array_type_t, Deleter> ptr;
public:
static ArrayType create(const Engine &engine, const FieldType &field) {
static_assert(sizeof(FieldType) == sizeof(wasmtime_field_type_t));
auto *raw = wasmtime_array_type_new(
engine.capi(), reinterpret_cast<const wasmtime_field_type_t *>(&field));
ArrayType ty;
ty.ptr.reset(raw);
return ty;
}
const wasmtime_array_type_t *capi() const { return ptr.get(); }
private:
ArrayType() = default;
friend class ArrayRefPre;
};
class ArrayRefPre {
friend class ArrayRef;
WASMTIME_OWN_WRAPPER(ArrayRefPre, wasmtime_array_ref_pre)
public:
static ArrayRefPre create(Store::Context cx, const ArrayType &ty) {
auto *raw = wasmtime_array_ref_pre_new(cx.capi(), ty.capi());
ArrayRefPre pre(raw);
return pre;
}
};
class ArrayRef {
friend class EqRef;
friend class Val;
friend class AnyRef;
wasmtime_arrayref_t val;
public:
explicit ArrayRef(wasmtime_arrayref_t val) : val(val) {}
ArrayRef(const ArrayRef &other) { wasmtime_arrayref_clone(&other.val, &val); }
ArrayRef &operator=(const ArrayRef &other) {
wasmtime_arrayref_unroot(&val);
wasmtime_arrayref_clone(&other.val, &val);
return *this;
}
ArrayRef(ArrayRef &&other) {
val = other.val;
wasmtime_arrayref_set_null(&other.val);
}
ArrayRef &operator=(ArrayRef &&other) {
wasmtime_arrayref_unroot(&val);
val = other.val;
wasmtime_arrayref_set_null(&other.val);
return *this;
}
~ArrayRef() { wasmtime_arrayref_unroot(&val); }
static Result<ArrayRef> create(Store::Context cx, const ArrayRefPre &pre,
const Val &elem, uint32_t len) {
wasmtime_arrayref_t out;
auto *err =
wasmtime_arrayref_new(cx.capi(), pre.capi(), &elem.val, len, &out);
if (err)
return Result<ArrayRef>(Error(err));
return Result<ArrayRef>(ArrayRef(out));
}
Result<uint32_t> len(Store::Context cx) const {
uint32_t out;
auto *err = wasmtime_arrayref_len(cx.capi(), &val, &out);
if (err)
return Result<uint32_t>(Error(err));
return Result<uint32_t>(out);
}
Result<Val> get(Store::Context cx, uint32_t index) const {
wasmtime_val_t out;
auto *err = wasmtime_arrayref_get(cx.capi(), &val, index, &out);
if (err)
return Result<Val>(Error(err));
return Result<Val>(Val(out));
}
Result<std::monostate> set(Store::Context cx, uint32_t index,
const Val &value) const {
auto *err = wasmtime_arrayref_set(cx.capi(), &val, index, &value.val);
if (err)
return Result<std::monostate>(Error(err));
return Result<std::monostate>(std::monostate{});
}
AnyRef to_anyref() const {
wasmtime_anyref_t out;
wasmtime_arrayref_to_anyref(&val, &out);
return AnyRef(out);
}
EqRef to_eqref() const {
wasmtime_eqref_t out;
wasmtime_arrayref_to_eqref(&val, &out);
return EqRef(out);
}
};
inline ArrayRef EqRef::as_array(Store::Context cx) const {
wasmtime_arrayref_t out;
wasmtime_eqref_as_array(cx.capi(), &val, &out);
return ArrayRef(out);
}
inline bool AnyRef::is_eqref(Store::Context cx) const {
return wasmtime_anyref_is_eqref(cx.capi(), &val);
}
inline bool AnyRef::is_struct(Store::Context cx) const {
return wasmtime_anyref_is_struct(cx.capi(), &val);
}
inline bool AnyRef::is_array(Store::Context cx) const {
return wasmtime_anyref_is_array(cx.capi(), &val);
}
inline std::optional<EqRef> AnyRef::as_eqref(Store::Context cx) const {
wasmtime_eqref_t out;
if (wasmtime_anyref_as_eqref(cx.capi(), &val, &out))
return EqRef(out);
return std::nullopt;
}
inline std::optional<StructRef> AnyRef::as_struct(Store::Context cx) const {
wasmtime_structref_t out;
if (wasmtime_anyref_as_struct(cx.capi(), &val, &out))
return StructRef(out);
return std::nullopt;
}
inline std::optional<ArrayRef> AnyRef::as_array(Store::Context cx) const {
wasmtime_arrayref_t out;
if (wasmtime_anyref_as_array(cx.capi(), &val, &out))
return ArrayRef(out);
return std::nullopt;
}
}
#endif