229 lines
10 KiB
C++
229 lines
10 KiB
C++
#ifndef PKMNLIB_HELPERFILE_H
|
|
#define PKMNLIB_HELPERFILE_H
|
|
#include <Arbutils/Memory/Memory.hpp>
|
|
#include <memory>
|
|
#include <sstream>
|
|
#include <type_traits>
|
|
#include <wasm.h>
|
|
#include "../WebAssemblyScriptResolver.hpp"
|
|
#include "wasm.h"
|
|
|
|
template <typename Test, template <typename...> class Ref> struct is_specialization : std::false_type {};
|
|
template <template <typename...> class Ref, typename... Args>
|
|
struct is_specialization<Ref<Args...>, Ref> : std::true_type {};
|
|
template <template <typename...> class Ref, typename... Args>
|
|
struct is_specialization<const Ref<Args...>&, Ref> : std::true_type {};
|
|
template <template <typename...> class Ref, typename... Args>
|
|
struct is_specialization<Ref<Args...>&, Ref> : std::true_type {};
|
|
|
|
struct WasmHelpers {
|
|
public:
|
|
static wasm_trap_t* CreateTrapFromException(const ArbUt::Exception& e, const WebAssemblyScriptResolver* resolver) {
|
|
std::stringstream ss;
|
|
ss << e.what() << std::endl;
|
|
ss << e.GetStacktrace() << std::endl;
|
|
|
|
wasm_message_t message;
|
|
wasm_name_new_from_string_nt(&message, ss.str().c_str());
|
|
wasm_trap_t* trap = wasm_trap_new(resolver->GetStore(), &message);
|
|
wasm_name_delete(&message);
|
|
return trap;
|
|
}
|
|
|
|
static wasm_trap_t* FromStdException(const std::exception& e, const WebAssemblyScriptResolver* resolver) {
|
|
wasm_message_t message;
|
|
wasm_name_new_from_string_nt(&message, e.what());
|
|
wasm_trap_t* trap = wasm_trap_new(resolver->GetStore(), &message);
|
|
wasm_name_delete(&message);
|
|
return trap;
|
|
}
|
|
|
|
template <typename T, typename R, R (T::*Method)() const>
|
|
static wasm_func_t* RegisterGetter(WebAssemblyScriptResolver* resolver) {
|
|
wasm_functype_t* type = wasm_functype_new_1_1(wasm_valtype_new_i64(), GetValType<R>());
|
|
auto* f = wasm_func_new_with_env(
|
|
resolver->GetStore(), type,
|
|
[](void* env, const wasm_val_vec_t* args, wasm_val_vec_t* returns) -> wasm_trap_t* {
|
|
try {
|
|
auto obj = (const T*)args->data[0].of.i64;
|
|
returns->data[0] = ToVal<R>((obj->*Method)());
|
|
} catch (ArbUt::Exception& e) {
|
|
return CreateTrapFromException(e, (WebAssemblyScriptResolver*)env);
|
|
} catch (std::exception& e) {
|
|
return FromStdException(e, (WebAssemblyScriptResolver*)env);
|
|
}
|
|
return nullptr;
|
|
},
|
|
resolver, nullptr);
|
|
wasm_functype_delete(type);
|
|
return f;
|
|
}
|
|
|
|
template <typename T> inline static T ConvertAllArguments(const wasm_val_vec_t* t, std::size_t& index) {
|
|
return FromVal<T>(t->data[index++]);
|
|
}
|
|
|
|
template <class R, class... Args>
|
|
static wasm_func_t* CreateFunc(WebAssemblyScriptResolver* resolver,
|
|
R (*func)(WebAssemblyScriptResolver*, Args...)) {
|
|
auto funcType = GetFuncType<R, Args...>();
|
|
struct Env {
|
|
WebAssemblyScriptResolver* Resolver;
|
|
R (*Func)(WebAssemblyScriptResolver*, Args...);
|
|
~Env() {}
|
|
};
|
|
|
|
auto env = new Env{.Resolver = resolver, .Func = func};
|
|
auto* f = wasm_func_new_with_env(
|
|
resolver->GetStore(), funcType,
|
|
[](void* env, const wasm_val_vec_t* parameters, wasm_val_vec_t* results) -> wasm_trap_t* {
|
|
auto e = *(Env*)env;
|
|
size_t index = 0;
|
|
try {
|
|
if constexpr (std::is_void<R>()) {
|
|
e.Func(e.Resolver, ConvertAllArguments<Args>(parameters, index)...);
|
|
} else if constexpr (std::is_same<R, wasm_trap_t*>()) {
|
|
return e.Func(e.Resolver, ConvertAllArguments<Args>(parameters, index)...);
|
|
} else {
|
|
R result = e.Func(e.Resolver, ConvertAllArguments<Args>(parameters, index)...);
|
|
results->data[0] = ToVal<R>(result);
|
|
}
|
|
} catch (ArbUt::Exception& exception) {
|
|
return CreateTrapFromException(exception, e.Resolver);
|
|
} catch (std::exception& exception) {
|
|
return FromStdException(exception, e.Resolver);
|
|
}
|
|
return nullptr;
|
|
},
|
|
env, [](void* env) { delete (Env*)env; });
|
|
wasm_functype_delete(funcType);
|
|
return f;
|
|
}
|
|
|
|
private:
|
|
template <class T> inline static wasm_valtype_t* GetValType() {
|
|
if constexpr (std::is_pointer<T>() || is_specialization<T, ArbUt::BorrowedPtr>::value ||
|
|
is_specialization<T, ArbUt::OptionalBorrowedPtr>::value ||
|
|
is_specialization<T, std::unique_ptr>::value) {
|
|
return wasm_valtype_new_i64();
|
|
} else if constexpr (std::is_enum<T>() || std::is_integral<T>()) {
|
|
if constexpr (sizeof(T) > 4) {
|
|
return wasm_valtype_new_i64();
|
|
} else {
|
|
return wasm_valtype_new_i32();
|
|
}
|
|
} else if constexpr (std::is_floating_point<T>()) {
|
|
if constexpr (sizeof(T) > 4) {
|
|
return wasm_valtype_new_f64();
|
|
} else {
|
|
return wasm_valtype_new_f32();
|
|
}
|
|
} else if constexpr (std::is_same<T, const ArbUt::StringView&>()) {
|
|
return wasm_valtype_new_i64();
|
|
} else if constexpr (is_specialization<T, ArbUt::List>()) {
|
|
return wasm_valtype_new_i64();
|
|
} else if constexpr (is_specialization<T, ArbUt::OptionalUniquePtrList>()) {
|
|
return wasm_valtype_new_i64();
|
|
} else {
|
|
static_assert(always_false<T>::value, "Unhandled value type");
|
|
}
|
|
}
|
|
|
|
template <typename T> struct always_false {
|
|
enum { value = false };
|
|
};
|
|
|
|
template <typename T> inline static wasm_val_t ToVal(const T& val) {
|
|
if constexpr (std::is_pointer<T>()) {
|
|
return WASM_I64_VAL(reinterpret_cast<i64>(val));
|
|
} else if constexpr (is_specialization<T, ArbUt::BorrowedPtr>::value) {
|
|
return WASM_I64_VAL(reinterpret_cast<i64>(val.GetRaw()));
|
|
} else if constexpr (is_specialization<T, ArbUt::OptionalBorrowedPtr>::value) {
|
|
if (val.HasValue()) {
|
|
return WASM_I64_VAL(reinterpret_cast<i64>(val.GetValue()));
|
|
}
|
|
return WASM_I64_VAL(0);
|
|
} else if constexpr (is_specialization<T, std::unique_ptr>::value) {
|
|
return WASM_I64_VAL(reinterpret_cast<i64>(val.get()));
|
|
} else if constexpr (std::is_enum<T>() || std::is_integral<T>()) {
|
|
if constexpr (sizeof(T) > 4) {
|
|
return WASM_I64_VAL((i64)val);
|
|
} else {
|
|
return WASM_I32_VAL((i32)val);
|
|
}
|
|
} else if constexpr (std::is_floating_point<T>()) {
|
|
if constexpr (sizeof(T) > 4) {
|
|
return WASM_F64_VAL((f64)val);
|
|
} else {
|
|
return WASM_F32_VAL((f32)val);
|
|
}
|
|
} else if constexpr (std::is_same<T, const ArbUt::StringView&>()) {
|
|
auto v = &val;
|
|
return WASM_I64_VAL(reinterpret_cast<i64>(v));
|
|
} else if constexpr (is_specialization<T, ArbUt::List>()) {
|
|
auto v = &val;
|
|
return WASM_I64_VAL(reinterpret_cast<i64>(v));
|
|
} else if constexpr (is_specialization<T, ArbUt::OptionalUniquePtrList>()) {
|
|
auto v = &val;
|
|
return WASM_I64_VAL(reinterpret_cast<i64>(v));
|
|
} else {
|
|
static_assert(always_false<T>::value, "Unhandled value type");
|
|
}
|
|
}
|
|
|
|
template <typename T> inline static T FromVal(const wasm_val_t& val) {
|
|
if constexpr (std::is_pointer<T>()) {
|
|
return (T) reinterpret_cast<void*>(val.of.i64);
|
|
} else if constexpr (is_specialization<T, ArbUt::BorrowedPtr>::value) {
|
|
return dynamic_cast<T>(reinterpret_cast<void*>(val.of.i64));
|
|
} else if constexpr (is_specialization<T, ArbUt::OptionalBorrowedPtr>::value) {
|
|
return dynamic_cast<T>(reinterpret_cast<void*>(val.of.i64));
|
|
} else if constexpr (is_specialization<T, std::unique_ptr>::value) {
|
|
return dynamic_cast<T>(reinterpret_cast<void*>(val.of.i64));
|
|
} else if constexpr (std::is_enum<T>() || std::is_integral<T>()) {
|
|
if constexpr (sizeof(T) > 4) {
|
|
return static_cast<T>(val.of.i64);
|
|
} else {
|
|
return static_cast<T>(val.of.i32);
|
|
}
|
|
} else if constexpr (std::is_floating_point<T>()) {
|
|
if constexpr (sizeof(T) > 4) {
|
|
return static_cast<T>(val.of.f64);
|
|
} else {
|
|
return static_cast<T>(val.of.f32);
|
|
}
|
|
} else {
|
|
static_assert(always_false<T>::value, "Unhandled value type");
|
|
}
|
|
}
|
|
|
|
template <size_t I, class... Args> inline static void AppendArgument(wasm_valtype_t* array[]) {
|
|
using type = typename std::tuple_element<I, std::tuple<Args...>>::type;
|
|
array[I] = GetValType<type>();
|
|
if constexpr (I + 1 < sizeof...(Args)) {
|
|
AppendArgument<I + 1, Args...>(array);
|
|
}
|
|
}
|
|
|
|
template <class R, class... Args> static wasm_functype_t* GetFuncType() {
|
|
wasm_valtype_t* ps[sizeof...(Args)];
|
|
AppendArgument<0, Args...>(ps);
|
|
|
|
wasm_valtype_vec_t params, results;
|
|
if constexpr (std::is_void<R>() || std::is_same<R, wasm_trap_t*>()) {
|
|
results = WASM_EMPTY_VEC;
|
|
} else {
|
|
wasm_valtype_t* rs[1] = {GetValType<R>()};
|
|
wasm_valtype_vec_new(&results, 1, rs);
|
|
}
|
|
wasm_valtype_vec_new(¶ms, sizeof...(Args), ps);
|
|
return wasm_functype_new(¶ms, &results);
|
|
}
|
|
};
|
|
|
|
#define REGISTER_GETTER(name, cType, cFunc, resolver) \
|
|
externs.Insert( \
|
|
name, WasmHelpers::RegisterGetter<cType, decltype(std::declval<cType>().cFunc()), &cType::cFunc>(resolver));
|
|
|
|
#endif // PKMNLIB_HELPERFILE_H
|