/*
* Copyright 2012 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/
#pragma once
#if __cplusplus < 201703L
#error "embind requires -std=c++17 or newer"
#endif
#include <emscripten/em_asm.h>
#include <emscripten/val.h>
#include <emscripten/wire.h>
#include <cassert>
#include <cstddef>
#include <functional>
#include <map>
#include <optional>
#include <string>
#include <type_traits>
#include <vector>
#if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer)
#include <sanitizer/lsan_interface.h>
#endif
namespace emscripten {
enum class sharing_policy {
NONE = 0,
INTRUSIVE = 1,
BY_EMVAL = 2,
};
namespace internal {
typedef int GenericEnumValue;
typedef void* GenericFunction;
typedef void (*VoidFunctionPtr)(void);
// Implemented in JavaScript. Don't call these directly.
extern "C" {
void _embind_fatal_error(
const char* name,
const char* payload) __attribute__((__noreturn__));
void _embind_register_void(
TYPEID voidType,
const char* name);
void _embind_register_bool(
TYPEID boolType,
const char* name,
bool trueValue,
bool falseValue);
void _embind_register_integer(
TYPEID integerType,
const char* name,
size_t size,
int32_t minRange,
uint32_t maxRange);
void _embind_register_bigint(
TYPEID integerType,
const char* name,
size_t size,
int64_t minRange,
uint64_t maxRange);
void _embind_register_float(
TYPEID floatType,
const char* name,
size_t size);
void _embind_register_std_string(
TYPEID stringType,
const char* name);
void _embind_register_std_wstring(
TYPEID stringType,
size_t charSize,
const char* name);
void _embind_register_emval(
TYPEID emvalType);
void _embind_register_memory_view(
TYPEID memoryViewType,
unsigned typedArrayIndex,
const char* name);
void _embind_register_function(
const char* name,
unsigned argCount,
const TYPEID argTypes[],
const char* signature,
GenericFunction invoker,
GenericFunction function,
bool isAsync,
bool isNonnullReturn);
void _embind_register_value_array(
TYPEID tupleType,
const char* name,
const char* constructorSignature,
GenericFunction constructor,
const char* destructorSignature,
GenericFunction destructor,
size_t valueSize,
bool isTrivial);
void _embind_register_value_array_element(
TYPEID tupleType,
TYPEID getterReturnType,
const char* getterSignature,
GenericFunction getter,
void* getterContext,
TYPEID setterArgumentType,
const char* setterSignature,
GenericFunction setter,
void* setterContext);
void _embind_finalize_value_array(TYPEID tupleType);
void _embind_register_value_object(
TYPEID structType,
const char* fieldName,
const char* constructorSignature,
GenericFunction constructor,
const char* destructorSignature,
GenericFunction destructor,
size_t valueSize,
bool isTrivial);
void _embind_register_value_object_field(
TYPEID structType,
const char* fieldName,
TYPEID getterReturnType,
const char* getterSignature,
GenericFunction getter,
void* getterContext,
TYPEID setterArgumentType,
const char* setterSignature,
GenericFunction setter,
void* setterContext);
void _embind_finalize_value_object(TYPEID structType);
void _embind_register_class(
TYPEID classType,
TYPEID pointerType,
TYPEID constPointerType,
TYPEID baseClassType,
const char* getActualTypeSignature,
GenericFunction getActualType,
const char* upcastSignature,
GenericFunction upcast,
const char* downcastSignature,
GenericFunction downcast,
const char* className,
const char* destructorSignature,
GenericFunction destructor);
void _embind_register_class_constructor(
TYPEID classType,
unsigned argCount,
const TYPEID argTypes[],
const char* invokerSignature,
GenericFunction invoker,
GenericFunction constructor);
void _embind_register_class_function(
TYPEID classType,
const char* methodName,
unsigned argCount,
const TYPEID argTypes[],
const char* invokerSignature,
GenericFunction invoker,
void* context,
unsigned isPureVirtual,
bool isAsync,
bool isNonnullReturn);
void _embind_register_class_property(
TYPEID classType,
const char* fieldName,
TYPEID getterReturnType,
const char* getterSignature,
GenericFunction getter,
void* getterContext,
TYPEID setterArgumentType,
const char* setterSignature,
GenericFunction setter,
void* setterContext);
void _embind_register_class_class_function(
TYPEID classType,
const char* methodName,
unsigned argCount,
const TYPEID argTypes[],
const char* invokerSignature,
GenericFunction invoker,
GenericFunction method,
bool isAsync,
bool isNonnullReturn);
void _embind_register_class_class_property(
TYPEID classType,
const char* fieldName,
TYPEID fieldType,
const void* fieldContext,
const char* getterSignature,
GenericFunction getter,
const char* setterSignature,
GenericFunction setter);
void _embind_register_iterable(
TYPEID classType,
TYPEID elementType,
const char* sizeMethodName,
const char* getMethodName);
EM_VAL _embind_create_inheriting_constructor(
const char* constructorName,
TYPEID wrapperType,
EM_VAL properties);
void _embind_register_enum(
TYPEID enumType,
const char* name,
size_t size,
bool isSigned,
int policyValue);
void _embind_register_smart_ptr(
TYPEID pointerType,
TYPEID pointeeType,
const char* pointerName,
sharing_policy sharingPolicy,
const char* getPointeeSignature,
GenericFunction getPointee,
const char* constructorSignature,
GenericFunction constructor,
const char* shareSignature,
GenericFunction share,
const char* destructorSignature,
GenericFunction destructor);
void _embind_register_enum_value(
TYPEID enumType,
const char* valueName,
GenericEnumValue value);
void _embind_register_constant(
const char* name,
TYPEID constantType,
double value);
void _embind_register_optional(
TYPEID optionalType,
TYPEID type);
void _embind_register_user_type(
TYPEID type,
const char* typeName);
void _embind_register_user_type_definition(
TYPEID type,
const char* typeName,
const char* typeDefinition);
// Register an InitFunc in the global linked list of init functions.
void _embind_register_bindings(struct InitFunc* f);
// Binding initialization functions registered by EMSCRIPTEN_BINDINGS macro
// below. Stored as linked list of static data object avoiding std containers
// to avoid static constructor ordering issues.
struct InitFunc {
InitFunc(void (*init_func)()) : init_func(init_func) {
// This calls the function immediately upon construction, and also registers
// it so that it can be called again on each worker that starts.
init_func();
_embind_register_bindings(this);
}
void (*init_func)();
InitFunc* next = nullptr;
};
} // end extern "C"
} // end namespace internal
////////////////////////////////////////////////////////////////////////////////
// select_overload and select_const
////////////////////////////////////////////////////////////////////////////////
template<typename Signature>
Signature* select_overload(Signature* fn) {
return fn;
}
template<typename Signature, typename ClassType>
auto select_overload(Signature (ClassType::*fn)) -> decltype(fn) {
return fn;
}
template<typename ClassType, typename ReturnType, typename... Args>
auto select_const(ReturnType (ClassType::*method)(Args...) const) -> decltype(method) {
return method;
}
namespace internal {
// this should be in <type_traits>, but alas, it's not
template<typename T> struct remove_class;
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...)> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); };
template<typename C, typename R, typename... A>
struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); };
template<typename LambdaType>
using LambdaSignature = typename remove_class<
decltype(&LambdaType::operator())
>::type;
} // end namespace internal
// requires captureless lambda because implicitly coerces to function pointer
template<typename LambdaType>
internal::LambdaSignature<LambdaType>* optional_override(const LambdaType& fp) {
return fp;
}
////////////////////////////////////////////////////////////////////////////////
// Invoker
////////////////////////////////////////////////////////////////////////////////
namespace internal {
template<typename ReturnPolicy, typename ReturnType, typename... Args>
struct Invoker {
static typename internal::BindingType<ReturnType>::WireType invoke(
ReturnType (*fn)(Args...),
typename internal::BindingType<Args>::WireType... args
) {
return internal::BindingType<ReturnType>::toWireType(
fn(internal::BindingType<Args>::fromWireType(args)...),
ReturnPolicy{}
);
}
};
template<typename ReturnPolicy, typename... Args>
struct Invoker<ReturnPolicy, void, Args...> {
static void invoke(
void (*fn)(Args...),
typename internal::BindingType<Args>::WireType... args
) {
return fn(
internal::BindingType<Args>::fromWireType(args)...
);
}
};
template<typename ReturnPolicy, typename FunctorType, typename ReturnType, typename... Args>
struct FunctorInvoker {
static typename internal::BindingType<ReturnType>::WireType invoke(
FunctorType& function,
typename internal::BindingType<Args>::WireType... args
) {
return internal::BindingType<ReturnType>::toWireType(
function(
internal::BindingType<Args>::fromWireType(args)...)
, ReturnPolicy{}
);
}
};
template<typename ReturnPolicy, typename FunctorType, typename... Args>
struct FunctorInvoker<ReturnPolicy, FunctorType, void, Args...> {
static void invoke(
FunctorType& function,
typename internal::BindingType<Args>::WireType... args
) {
function(
internal::BindingType<Args>::fromWireType(args)...);
}
};
} // end namespace internal
////////////////////////////////////////////////////////////////////////////////
// SignatureCode, SignatureString
////////////////////////////////////////////////////////////////////////////////
namespace internal {
// TODO: this is a historical default, but we should probably use 'p' instead,
// and only enable it for smart_ptr_trait<> descendants.
template<typename T, typename = decltype(__em_asm_sig<int>::value)>
struct SignatureCode : __em_asm_sig<int> {};
template<typename T>
struct SignatureCode<T, decltype(__em_asm_sig<T>::value)> : __em_asm_sig<T> {};
template<typename T>
struct SignatureCode<T&> : SignatureCode<T*> {};
template<>
struct SignatureCode<void> {
static constexpr char value = 'v';
};
template<typename... Args>
constexpr const char Signature[] = { SignatureCode<Args>::value..., 0 };
template<typename Return, typename... Args>
constexpr const char* getSignature(Return (*)(Args...)) {
return Signature<Return, Args...>;
}
} // end namespace internal
////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS
////////////////////////////////////////////////////////////////////////////////
template<typename ReturnType, typename... Args, typename... Policies>
void function(const char* name, ReturnType (*fn)(Args...), Policies...) {
using namespace internal;
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args;
using ReturnPolicy = typename GetReturnValuePolicy<ReturnType, Policies...>::tag;
auto invoke = Invoker<ReturnPolicy, ReturnType, Args...>::invoke;
_embind_register_function(
name,
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
reinterpret_cast<GenericFunction>(fn),
isAsync<Policies...>::value,
isNonnullReturn<Policies...>::value);
}
namespace internal {
template<typename ClassType, typename... Args>
ClassType* operator_new(Args&&... args) {
return new ClassType(std::forward<Args>(args)...);
}
template<typename WrapperType, typename ClassType, typename... Args>
WrapperType wrapped_new(Args&&... args) {
return WrapperType(new ClassType(std::forward<Args>(args)...));
}
template<typename ClassType, typename... Args>
ClassType* raw_constructor(
typename internal::BindingType<Args>::WireType... args
) {
return new ClassType(
internal::BindingType<Args>::fromWireType(args)...
);
}
template<typename ClassType>
void raw_destructor(ClassType* ptr) {
delete ptr;
}
// Argument temporaries of trivial value types are placed on the wasm stack.
// Stack temporaries come from stackAlloc, which guarantees STACK_ALIGN
// (== __BIGGEST_ALIGNMENT__) alignment; over-aligned types keep the heap path.
template<typename ClassType>
struct is_trivial_value_type {
static constexpr bool value =
std::is_trivially_constructible<ClassType>::value &&
std::is_trivially_destructible<ClassType>::value &&
alignof(ClassType) <= __BIGGEST_ALIGNMENT__;
};
template<typename ReturnPolicy, typename FunctionPointerType, typename ReturnType, typename ThisType, typename... Args>
struct FunctionInvoker {
static typename internal::BindingType<ReturnType>::WireType invoke(
FunctionPointerType* function,
typename internal::BindingType<ThisType>::WireType wireThis,
typename internal::BindingType<Args>::WireType... args
) {
return internal::BindingType<ReturnType>::toWireType(
(*function)(
internal::BindingType<ThisType>::fromWireType(wireThis),
internal::BindingType<Args>::fromWireType(args)...),
ReturnPolicy{}
);
}
};
template<typename ReturnPolicy, typename FunctionPointerType, typename ThisType, typename... Args>
struct FunctionInvoker<ReturnPolicy, FunctionPointerType, void, ThisType, Args...> {
static void invoke(
FunctionPointerType* function,
typename internal::BindingType<ThisType>::WireType wireThis,
typename internal::BindingType<Args>::WireType... args
) {
(*function)(
internal::BindingType<ThisType>::fromWireType(wireThis),
internal::BindingType<Args>::fromWireType(args)...);
}
};
template<typename ReturnPolicy,
typename MemberPointer,
typename ReturnType,
typename ThisType,
typename... Args>
struct MethodInvoker {
static typename internal::BindingType<ReturnType>::WireType invoke(
const MemberPointer& method,
typename internal::BindingType<ThisType>::WireType wireThis,
typename internal::BindingType<Args>::WireType... args
) {
return internal::BindingType<ReturnType>::toWireType(
(internal::BindingType<ThisType>::fromWireType(wireThis)->*method)(
internal::BindingType<Args>::fromWireType(args)...
)
,
ReturnPolicy{}
);
}
};
template<typename ReturnPolicy,
typename MemberPointer,
typename ThisType,
typename... Args>
struct MethodInvoker<ReturnPolicy, MemberPointer, void, ThisType, Args...> {
static void invoke(
const MemberPointer& method,
typename internal::BindingType<ThisType>::WireType wireThis,
typename internal::BindingType<Args>::WireType... args
) {
return (internal::BindingType<ThisType>::fromWireType(wireThis)->*method)(
internal::BindingType<Args>::fromWireType(args)...
);
}
};
template<typename InstanceType, typename MemberType>
struct MemberAccess {
typedef MemberType InstanceType::*MemberPointer;
typedef internal::BindingType<MemberType> MemberBinding;
typedef typename MemberBinding::WireType WireType;
template<typename ClassType, typename ReturnPolicy = rvp::default_tag>
static WireType getWire(
const MemberPointer& field,
ClassType& ptr
) {
return MemberBinding::toWireType(ptr.*field, ReturnPolicy{});
}
template<typename ClassType>
static void setWire(
const MemberPointer& field,
ClassType& ptr,
WireType value
) {
ptr.*field = MemberBinding::fromWireType(value);
}
};
template<typename FieldType>
struct GlobalAccess {
typedef internal::BindingType<FieldType> MemberBinding;
typedef typename MemberBinding::WireType WireType;
static WireType get(FieldType* context) {
return MemberBinding::toWireType(*context, rvp::default_tag{});
}
static void set(FieldType* context, WireType value) {
*context = MemberBinding::fromWireType(value);
}
};
// TODO: This could do a reinterpret-cast if sizeof(T) === sizeof(void*)
template<typename T>
inline T* getContext(const T& t) {
// not a leak because this is called once per binding
auto* ret = new T(t);
#if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer)
__lsan_ignore_object(ret);
#endif
return ret;
}
template<typename Func, typename ValueTypeOrSignature>
struct FunctionTag {};
template<typename T>
struct GetterPolicy;
template<typename GetterReturnType, typename GetterThisType>
struct GetterPolicy<GetterReturnType (GetterThisType::*)() const> {
typedef GetterReturnType ReturnType;
typedef GetterReturnType (GetterThisType::*Context)() const;
typedef internal::BindingType<ReturnType> Binding;
typedef typename Binding::WireType WireType;
template<typename ClassType, typename ReturnPolicy>
static WireType get(const Context& context, const ClassType& ptr) {
return Binding::toWireType((ptr.*context)(), ReturnPolicy{});
}
static void* getContext(Context context) {
return internal::getContext(context);
}
};
#ifdef __cpp_noexcept_function_type
template<typename GetterReturnType, typename GetterThisType>
struct GetterPolicy<GetterReturnType (GetterThisType::*)() const noexcept>
: GetterPolicy<GetterReturnType (GetterThisType::*)() const> {};
#endif
template<typename GetterReturnType, typename GetterThisType>
struct GetterPolicy<GetterReturnType (*)(const GetterThisType&)> {
typedef GetterReturnType ReturnType;
typedef GetterReturnType (*Context)(const GetterThisType&);
typedef internal::BindingType<ReturnType> Binding;
typedef typename Binding::WireType WireType;
template<typename ClassType, typename ReturnPolicy>
static WireType get(const Context& context, const ClassType& ptr) {
return Binding::toWireType(context(ptr), ReturnPolicy{});
}
static void* getContext(Context context) {
return internal::getContext(context);
}
};
template<typename GetterReturnType, typename GetterThisType>
struct GetterPolicy<std::function<GetterReturnType(const GetterThisType&)>> {
typedef GetterReturnType ReturnType;
typedef std::function<GetterReturnType(const GetterThisType&)> Context;
typedef internal::BindingType<ReturnType> Binding;
typedef typename Binding::WireType WireType;
template<typename ClassType, typename ReturnPolicy>
static WireType get(const Context& context, const ClassType& ptr) {
return Binding::toWireType(context(ptr), ReturnPolicy{});
}
static void* getContext(const Context& context) {
return internal::getContext(context);
}
};
template<typename Getter, typename GetterReturnType>
struct GetterPolicy<FunctionTag<Getter, GetterReturnType>> {
typedef GetterReturnType ReturnType;
typedef Getter Context;
typedef internal::BindingType<ReturnType> Binding;
typedef typename Binding::WireType WireType;
template<typename ClassType, typename ReturnPolicy>
static WireType get(const Context& context, const ClassType& ptr) {
return Binding::toWireType(context(ptr), ReturnPolicy{});
}
static void* getContext(const Context& context) {
return internal::getContext(context);
}
};
template<typename T>
struct SetterPolicy;
template<typename SetterReturnType, typename SetterThisType, typename SetterArgumentType>
struct SetterPolicy<SetterReturnType (SetterThisType::*)(SetterArgumentType)> {
typedef SetterArgumentType ArgumentType;
typedef SetterReturnType (SetterThisType::*Context)(SetterArgumentType);
typedef internal::BindingType<SetterArgumentType> Binding;
typedef typename Binding::WireType WireType;
template<typename ClassType>
static void set(const Context& context, ClassType& ptr, WireType wt) {
(ptr.*context)(Binding::fromWireType(wt));
}
static void* getContext(Context context) {
return internal::getContext(context);
}
};
#ifdef __cpp_noexcept_function_type
template<typename SetterReturnType, typename SetterThisType, typename SetterArgumentType>
struct SetterPolicy<SetterReturnType (SetterThisType::*)(SetterArgumentType) noexcept>
: SetterPolicy<SetterReturnType (SetterThisType::*)(SetterArgumentType)> {};
#endif
template<typename SetterReturnType, typename SetterThisType, typename SetterArgumentType>
struct SetterPolicy<SetterReturnType (*)(SetterThisType&, SetterArgumentType)> {
typedef SetterArgumentType ArgumentType;
typedef SetterReturnType (*Context)(SetterThisType&, SetterArgumentType);
typedef internal::BindingType<SetterArgumentType> Binding;
typedef typename Binding::WireType WireType;
template<typename ClassType>
static void set(const Context& context, ClassType& ptr, WireType wt) {
context(ptr, Binding::fromWireType(wt));
}
static void* getContext(Context context) {
return internal::getContext(context);
}
};
template<typename SetterReturnType, typename SetterThisType, typename SetterArgumentType>
struct SetterPolicy<std::function<SetterReturnType(SetterThisType&, SetterArgumentType)>> {
typedef SetterArgumentType ArgumentType;
typedef std::function<SetterReturnType(SetterThisType&, SetterArgumentType)> Context;
typedef internal::BindingType<SetterArgumentType> Binding;
typedef typename Binding::WireType WireType;
template<typename ClassType>
static void set(const Context& context, ClassType& ptr, WireType wt) {
context(ptr, Binding::fromWireType(wt));
}
static void* getContext(const Context& context) {
return internal::getContext(context);
}
};
template<typename Setter, typename SetterArgumentType>
struct SetterPolicy<FunctionTag<Setter, SetterArgumentType>> {
typedef SetterArgumentType ArgumentType;
typedef Setter Context;
typedef internal::BindingType<SetterArgumentType> Binding;
typedef typename Binding::WireType WireType;
template<typename ClassType>
static void set(const Context& context, ClassType& ptr, WireType wt) {
context(ptr, Binding::fromWireType(wt));
}
static void* getContext(const Context& context) {
return internal::getContext(context);
}
};
class noncopyable {
protected:
noncopyable() {}
~noncopyable() {}
private:
noncopyable(const noncopyable&) = delete;
const noncopyable& operator=(const noncopyable&) = delete;
};
template<typename ClassType, typename ElementType>
typename BindingType<ElementType>::WireType get_by_index(int index, ClassType& ptr) {
return BindingType<ElementType>::toWireType(ptr[index], rvp::default_tag{});
}
template<typename ClassType, typename ElementType>
void set_by_index(int index, ClassType& ptr, typename BindingType<ElementType>::WireType wt) {
ptr[index] = BindingType<ElementType>::fromWireType(wt);
}
} // end namespace internal
template<int Index>
struct index {
};
////////////////////////////////////////////////////////////////////////////////
// VALUE TUPLES
////////////////////////////////////////////////////////////////////////////////
template<typename ClassType>
class value_array : public internal::noncopyable {
public:
typedef ClassType class_type;
value_array(const char* name) {
using namespace internal;
auto constructor = &raw_constructor<ClassType>;
auto destructor = &raw_destructor<ClassType>;
_embind_register_value_array(
TypeID<ClassType>::get(),
name,
getSignature(constructor),
reinterpret_cast<GenericFunction>(constructor),
getSignature(destructor),
reinterpret_cast<GenericFunction>(destructor),
sizeof(ClassType),
is_trivial_value_type<ClassType>::value);
}
~value_array() {
using namespace internal;
_embind_finalize_value_array(TypeID<ClassType>::get());
}
template<typename InstanceType, typename ElementType>
value_array& element(ElementType InstanceType::*field) {
using namespace internal;
auto getter = &MemberAccess<InstanceType, ElementType>
::template getWire<ClassType>;
auto setter = &MemberAccess<InstanceType, ElementType>
::template setWire<ClassType>;
_embind_register_value_array_element(
TypeID<ClassType>::get(),
TypeID<ElementType>::get(),
getSignature(getter),
reinterpret_cast<GenericFunction>(getter),
getContext(field),
TypeID<ElementType>::get(),
getSignature(setter),
reinterpret_cast<GenericFunction>(setter),
getContext(field));
return *this;
}
template<typename Getter, typename Setter>
value_array& element(Getter getter, Setter setter) {
using namespace internal;
typedef GetterPolicy<Getter> GP;
typedef SetterPolicy<Setter> SP;
auto g = &GP::template get<ClassType, rvp::default_tag>;
auto s = &SP::template set<ClassType>;
_embind_register_value_array_element(
TypeID<ClassType>::get(),
TypeID<typename GP::ReturnType>::get(),
getSignature(g),
reinterpret_cast<GenericFunction>(g),
GP::getContext(getter),
TypeID<typename SP::ArgumentType>::get(),
getSignature(s),
reinterpret_cast<GenericFunction>(s),
SP::getContext(setter));
return *this;
}
template<int Index>
value_array& element(index<Index>) {
using namespace internal;
ClassType* null = 0;
typedef typename std::remove_reference<decltype((*null)[Index])>::type ElementType;
auto getter = &internal::get_by_index<ClassType, ElementType>;
auto setter = &internal::set_by_index<ClassType, ElementType>;
_embind_register_value_array_element(
TypeID<ClassType>::get(),
TypeID<ElementType>::get(),
getSignature(getter),
reinterpret_cast<GenericFunction>(getter),
reinterpret_cast<void*>(Index),
TypeID<ElementType>::get(),
getSignature(setter),
reinterpret_cast<GenericFunction>(setter),
reinterpret_cast<void*>(Index));
return *this;
}
};
////////////////////////////////////////////////////////////////////////////////
// VALUE STRUCTS
////////////////////////////////////////////////////////////////////////////////
template<typename ClassType>
class value_object : public internal::noncopyable {
public:
typedef ClassType class_type;
value_object(const char* name) {
using namespace internal;
auto ctor = &raw_constructor<ClassType>;
auto dtor = &raw_destructor<ClassType>;
_embind_register_value_object(
TypeID<ClassType>::get(),
name,
getSignature(ctor),
reinterpret_cast<GenericFunction>(ctor),
getSignature(dtor),
reinterpret_cast<GenericFunction>(dtor),
sizeof(ClassType),
is_trivial_value_type<ClassType>::value);
}
~value_object() {
using namespace internal;
_embind_finalize_value_object(internal::TypeID<ClassType>::get());
}
template<typename InstanceType, typename FieldType>
value_object& field(const char* fieldName, FieldType InstanceType::*field) {
using namespace internal;
auto getter = &MemberAccess<InstanceType, FieldType>
::template getWire<ClassType>;
auto setter = &MemberAccess<InstanceType, FieldType>
::template setWire<ClassType>;
_embind_register_value_object_field(
TypeID<ClassType>::get(),
fieldName,
TypeID<FieldType>::get(),
getSignature(getter),
reinterpret_cast<GenericFunction>(getter),
getContext(field),
TypeID<FieldType>::get(),
getSignature(setter),
reinterpret_cast<GenericFunction>(setter),
getContext(field));
return *this;
}
template<typename InstanceType, typename ElementType, int N>
value_object& field(const char* fieldName, ElementType (InstanceType::*field)[N]) {
using namespace internal;
typedef std::array<ElementType, N> FieldType;
static_assert(sizeof(FieldType) == sizeof(ElementType[N]));
auto getter = &MemberAccess<InstanceType, FieldType>
::template getWire<ClassType>;
auto setter = &MemberAccess<InstanceType, FieldType>
::template setWire<ClassType>;
_embind_register_value_object_field(
TypeID<ClassType>::get(),
fieldName,
TypeID<FieldType>::get(),
getSignature(getter),
reinterpret_cast<GenericFunction>(getter),
getContext(field),
TypeID<FieldType>::get(),
getSignature(setter),
reinterpret_cast<GenericFunction>(setter),
getContext(field));
return *this;
}
template<typename Getter, typename Setter>
value_object& field(
const char* fieldName,
Getter getter,
Setter setter
) {
using namespace internal;
typedef GetterPolicy<Getter> GP;
typedef SetterPolicy<Setter> SP;
auto g = &GP::template get<ClassType, rvp::default_tag>;
auto s = &SP::template set<ClassType>;
_embind_register_value_object_field(
TypeID<ClassType>::get(),
fieldName,
TypeID<typename GP::ReturnType>::get(),
getSignature(g),
reinterpret_cast<GenericFunction>(g),
GP::getContext(getter),
TypeID<typename SP::ArgumentType>::get(),
getSignature(s),
reinterpret_cast<GenericFunction>(s),
SP::getContext(setter));
return *this;
}
template<int Index>
value_object& field(const char* fieldName, index<Index>) {
using namespace internal;
ClassType* null = 0;
typedef typename std::remove_reference<decltype((*null)[Index])>::type ElementType;
auto getter = &internal::get_by_index<ClassType, ElementType>;
auto setter = &internal::set_by_index<ClassType, ElementType>;
_embind_register_value_object_field(
TypeID<ClassType>::get(),
fieldName,
TypeID<ElementType>::get(),
getSignature(getter),
reinterpret_cast<GenericFunction>(getter),
reinterpret_cast<void*>(Index),
TypeID<ElementType>::get(),
getSignature(setter),
reinterpret_cast<GenericFunction>(setter),
reinterpret_cast<void*>(Index));
return *this;
}
};
////////////////////////////////////////////////////////////////////////////////
// SMART POINTERS
////////////////////////////////////////////////////////////////////////////////
template<typename PointerType>
struct default_smart_ptr_trait {
static sharing_policy get_sharing_policy() {
return sharing_policy::NONE;
}
static void* share(void* v) {
return 0; // no sharing
}
static PointerType* construct_null() {
return new PointerType;
}
};
// specialize if you have a different pointer type
template<typename PointerType>
struct smart_ptr_trait : public default_smart_ptr_trait<PointerType> {
typedef typename PointerType::element_type element_type;
static element_type* get(const PointerType& ptr) {
return ptr.get();
}
};
template<typename PointeeType>
struct smart_ptr_trait<std::shared_ptr<PointeeType>> {
typedef std::shared_ptr<PointeeType> PointerType;
typedef typename PointerType::element_type element_type;
static element_type* get(const PointerType& ptr) {
return ptr.get();
}
static sharing_policy get_sharing_policy() {
return sharing_policy::BY_EMVAL;
}
static std::shared_ptr<PointeeType>* share(PointeeType* p, EM_VAL v) {
return new std::shared_ptr<PointeeType>(
p,
val_deleter(val::take_ownership(v)));
}
static PointerType* construct_null() {
return new PointerType;
}
private:
class val_deleter {
public:
val_deleter() = delete;
explicit val_deleter(val v)
: v(v)
{}
void operator()(void const*) {
v();
// eventually we'll need to support emptied out val
v = val::undefined();
}
private:
val v;
};
};
////////////////////////////////////////////////////////////////////////////////
// CLASSES
////////////////////////////////////////////////////////////////////////////////
namespace internal {
class WrapperBase {
public:
void setNotifyJSOnDestruction(bool notify) {
notifyJSOnDestruction = notify;
}
protected:
bool notifyJSOnDestruction = false;
};
} // end namespace internal
// abstract classes
template<typename T>
class wrapper : public T, public internal::WrapperBase {
public:
typedef T class_type;
template<typename... Args>
explicit wrapper(val&& wrapped, Args&&... args)
: T(std::forward<Args>(args)...)
, wrapped(std::forward<val>(wrapped))
{}
~wrapper() {
if (notifyJSOnDestruction) {
call<void>("__destruct");
}
}
template<typename ReturnType, typename... Args>
ReturnType call(const char* name, Args&&... args) const {
return wrapped.call<ReturnType>(name, std::forward<Args>(args)...);
}
private:
val wrapped;
};
#define EMSCRIPTEN_WRAPPER(T) \
template<typename... Args> \
T(::emscripten::val&& v, Args&&... args) \
: wrapper(std::forward<::emscripten::val>(v), std::forward<Args>(args)...) \
{}
namespace internal {
struct NoBaseClass {
template<typename ClassType>
static void verify() {
}
static TYPEID get() {
return nullptr;
}
template<typename ClassType>
static VoidFunctionPtr getUpcaster() {
return nullptr;
}
template<typename ClassType>
static VoidFunctionPtr getDowncaster() {
return nullptr;
}
};
// NOTE: this returns the class type, not the pointer type
template<typename T>
inline TYPEID getActualType(T* ptr) {
return getLightTypeID(*ptr);
};
} // end namespace internal
template<typename BaseClass>
struct base {
typedef BaseClass class_type;
template<typename ClassType>
static void verify() {
static_assert(!std::is_same<ClassType, BaseClass>::value, "Base must not have same type as class");
static_assert(std::is_base_of<BaseClass, ClassType>::value, "Derived class must derive from base");
}
static internal::TYPEID get() {
return internal::TypeID<BaseClass>::get();
}
template<typename ClassType>
using Upcaster = BaseClass* (*)(ClassType*);
template<typename ClassType>
using Downcaster = ClassType* (*)(BaseClass*);
template<typename ClassType>
static Upcaster<ClassType> getUpcaster() {
return &convertPointer<ClassType, BaseClass>;
}
template<typename ClassType>
static Downcaster<ClassType> getDowncaster() {
return &convertPointer<BaseClass, ClassType>;
}
template<typename From, typename To>
static To* convertPointer(From* ptr) {
return static_cast<To*>(ptr);
}
};
namespace internal {
template<typename WrapperType>
val wrapped_extend(const std::string& name, const val& properties) {
return val::take_ownership(_embind_create_inheriting_constructor(
name.c_str(),
TypeID<WrapperType>::get(),
properties.as_handle()));
}
} // end namespace internal
namespace internal {
template<typename... Policies>
struct isPureVirtual;
template<typename... Rest>
struct isPureVirtual<pure_virtual, Rest...> {
static constexpr bool value = true;
};
template<typename T, typename... Rest>
struct isPureVirtual<T, Rest...> {
static constexpr bool value = isPureVirtual<Rest...>::value;
};
template<>
struct isPureVirtual<> {
static constexpr bool value = false;
};
struct DeduceArgumentsTag {};
////////////////////////////////////////////////////////////////////////////
// RegisterClassConstructor
////////////////////////////////////////////////////////////////////////////
template <typename T>
struct RegisterClassConstructor;
template<typename ReturnType, typename... Args>
struct RegisterClassConstructor<ReturnType (*)(Args...)> {
template <typename ClassType, typename... Policies>
static void invoke(ReturnType (*factory)(Args...)) {
typename WithPolicies<allow_raw_pointers, Policies...>::template ArgTypeList<ReturnType, Args...> args;
using ReturnPolicy = rvp::take_ownership;
auto invoke = &Invoker<ReturnPolicy, ReturnType, Args...>::invoke;
_embind_register_class_constructor(
TypeID<ClassType>::get(),
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
reinterpret_cast<GenericFunction>(factory));
}
};
template<typename ReturnType, typename... Args>
struct RegisterClassConstructor<std::function<ReturnType (Args...)>> {
template <typename ClassType, typename... Policies>
static void invoke(std::function<ReturnType (Args...)> factory) {
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args;
using ReturnPolicy = rvp::take_ownership;
auto invoke = &FunctorInvoker<ReturnPolicy, decltype(factory), ReturnType, Args...>::invoke;
_embind_register_class_constructor(
TypeID<ClassType>::get(),
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
reinterpret_cast<GenericFunction>(getContext(factory)));
}
};
template<typename Callable, typename ReturnType, typename... Args>
struct RegisterClassConstructor<FunctionTag<Callable, ReturnType (Args...)>> {
template <typename ClassType, typename... Policies>
static void invoke(Callable& factory) {
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args;
using ReturnPolicy = rvp::take_ownership;
auto invoke = &FunctorInvoker<ReturnPolicy, decltype(factory), ReturnType, Args...>::invoke;
_embind_register_class_constructor(
TypeID<ClassType>::get(),
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
reinterpret_cast<GenericFunction>(getContext(factory)));
}
};
////////////////////////////////////////////////////////////////////////////
// RegisterClassMethod
////////////////////////////////////////////////////////////////////////////
template <typename T>
struct RegisterClassMethod;
template<typename ClassType, typename ReturnType, typename... Args>
struct RegisterClassMethod<ReturnType (ClassType::*)(Args...)> {
template <typename CT, typename... Policies>
static void invoke(const char* methodName,
ReturnType (ClassType::*memberFunction)(Args...)) {
using ReturnPolicy = typename GetReturnValuePolicy<ReturnType, Policies...>::tag;
auto invoke = MethodInvoker<ReturnPolicy, decltype(memberFunction), ReturnType, ClassType*, Args...>::invoke;
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<ClassType>, Args...> args;
_embind_register_class_function(
TypeID<ClassType>::get(),
methodName,
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
getContext(memberFunction),
isPureVirtual<Policies...>::value,
isAsync<Policies...>::value,
isNonnullReturn<Policies...>::value);
}
};
#ifdef __cpp_noexcept_function_type
template<typename ClassType, typename ReturnType, typename... Args>
struct RegisterClassMethod<ReturnType (ClassType::*)(Args...) noexcept>
: RegisterClassMethod<ReturnType (ClassType::*)(Args...)> {};
#endif
template<typename ClassType, typename ReturnType, typename... Args>
struct RegisterClassMethod<ReturnType (ClassType::*)(Args...) const> {
template <typename CT, typename... Policies>
static void invoke(const char* methodName,
ReturnType (ClassType::*memberFunction)(Args...) const) {
using ReturnPolicy = typename GetReturnValuePolicy<ReturnType, Policies...>::tag;
auto invoke = MethodInvoker<ReturnPolicy, decltype(memberFunction), ReturnType, const ClassType*, Args...>::invoke;
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<const ClassType>, Args...> args;
_embind_register_class_function(
TypeID<ClassType>::get(),
methodName,
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
getContext(memberFunction),
isPureVirtual<Policies...>::value,
isAsync<Policies...>::value,
isNonnullReturn<Policies...>::value);
}
};
#ifdef __cpp_noexcept_function_type
template<typename ClassType, typename ReturnType, typename... Args>
struct RegisterClassMethod<ReturnType (ClassType::*)(Args...) const noexcept>
: RegisterClassMethod<ReturnType (ClassType::*)(Args...) const> {};
#endif
template<typename ReturnType, typename ThisType, typename... Args>
struct RegisterClassMethod<ReturnType (*)(ThisType, Args...)> {
template <typename ClassType, typename... Policies>
static void invoke(const char* methodName,
ReturnType (*function)(ThisType, Args...)) {
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, ThisType, Args...> args;
using ReturnPolicy = typename GetReturnValuePolicy<ReturnType, Policies...>::tag;
auto invoke = FunctionInvoker<ReturnPolicy, decltype(function), ReturnType, ThisType, Args...>::invoke;
_embind_register_class_function(
TypeID<ClassType>::get(),
methodName,
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
getContext(function),
false,
isAsync<Policies...>::value,
isNonnullReturn<Policies...>::value);
}
};
#ifdef __cpp_noexcept_function_type
template<typename ReturnType, typename ThisType, typename... Args>
struct RegisterClassMethod<ReturnType (*)(ThisType, Args...) noexcept>
: RegisterClassMethod<ReturnType (*)(ThisType, Args...)> {};
#endif
template<typename ReturnType, typename ThisType, typename... Args>
struct RegisterClassMethod<std::function<ReturnType (ThisType, Args...)>> {
template <typename ClassType, typename... Policies>
static void invoke(const char* methodName,
std::function<ReturnType (ThisType, Args...)> function) {
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, ThisType, Args...> args;
using ReturnPolicy = typename GetReturnValuePolicy<ReturnType, Policies...>::tag;
auto invoke = FunctorInvoker<ReturnPolicy, decltype(function), ReturnType, ThisType, Args...>::invoke;
_embind_register_class_function(
TypeID<ClassType>::get(),
methodName,
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
getContext(function),
false,
isAsync<Policies...>::value,
isNonnullReturn<Policies...>::value);
}
};
template<typename Callable, typename ReturnType, typename ThisType, typename... Args>
struct RegisterClassMethod<FunctionTag<Callable, ReturnType (ThisType, Args...)>> {
template <typename ClassType, typename... Policies>
static void invoke(const char* methodName,
Callable& callable) {
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, ThisType, Args...> args;
using ReturnPolicy = typename GetReturnValuePolicy<ReturnType, Policies...>::tag;
auto invoke = FunctorInvoker<ReturnPolicy, decltype(callable), ReturnType, ThisType, Args...>::invoke;
_embind_register_class_function(
TypeID<ClassType>::get(),
methodName,
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
getContext(callable),
false,
isAsync<Policies...>::value,
isNonnullReturn<Policies...>::value);
}
};
// Helper structs for shifting argument indices when a policy is applied.
template<typename Slot>
struct ShiftSlot {
using type = Slot;
};
template<int Index>
struct ShiftSlot<arg<Index>> {
using type = arg<Index + 1>;
};
template<typename Policy>
struct ShiftPolicy {
using type = Policy;
};
template<typename Slot>
struct ShiftPolicy<allow_raw_pointer<Slot>> {
using type = allow_raw_pointer<typename ShiftSlot<Slot>::type>;
};
template<typename Slot>
struct ShiftPolicy<nonnull<Slot>> {
using type = nonnull<typename ShiftSlot<Slot>::type>;
};
} // end namespace internal
template<typename... ConstructorArgs>
struct constructor {
};
template<typename ClassType, typename BaseSpecifier = internal::NoBaseClass>
class class_ {
public:
typedef ClassType class_type;
typedef BaseSpecifier base_specifier;
class_() = delete;
EMSCRIPTEN_ALWAYS_INLINE explicit class_(const char* name) {
using namespace internal;
BaseSpecifier::template verify<ClassType>();
auto _getActualType = &getActualType<ClassType>;
auto upcast = BaseSpecifier::template getUpcaster<ClassType>();
auto downcast = BaseSpecifier::template getDowncaster<ClassType>();
auto destructor = &raw_destructor<ClassType>;
_embind_register_class(
TypeID<ClassType>::get(),
TypeID<AllowedRawPointer<ClassType>>::get(),
TypeID<AllowedRawPointer<const ClassType>>::get(),
BaseSpecifier::get(),
getSignature(_getActualType),
reinterpret_cast<GenericFunction>(_getActualType),
getSignature(upcast),
reinterpret_cast<GenericFunction>(upcast),
getSignature(downcast),
reinterpret_cast<GenericFunction>(downcast),
name,
getSignature(destructor),
reinterpret_cast<GenericFunction>(destructor));
}
template<typename PointerType>
EMSCRIPTEN_ALWAYS_INLINE const class_& smart_ptr(const char* name) const {
using namespace internal;
typedef smart_ptr_trait<PointerType> PointerTrait;
typedef typename PointerTrait::element_type PointeeType;
static_assert(std::is_same<ClassType, typename std::remove_cv<PointeeType>::type>::value, "smart pointer must point to this class");
auto get = &PointerTrait::get;
auto construct_null = &PointerTrait::construct_null;
auto share = &PointerTrait::share;
auto destructor = &raw_destructor<PointerType>;
_embind_register_smart_ptr(
TypeID<PointerType>::get(),
TypeID<PointeeType>::get(),
name,
PointerTrait::get_sharing_policy(),
getSignature(get),
reinterpret_cast<GenericFunction>(get),
getSignature(construct_null),
reinterpret_cast<GenericFunction>(construct_null),
getSignature(share),
reinterpret_cast<GenericFunction>(share),
getSignature(destructor),
reinterpret_cast<GenericFunction>(destructor));
return *this;
};
template<typename... ConstructorArgs, typename... Policies>
EMSCRIPTEN_ALWAYS_INLINE const class_& constructor(Policies... policies) const {
return constructor(
&internal::operator_new<ClassType, ConstructorArgs...>,
policies...);
}
template<typename Signature = internal::DeduceArgumentsTag, typename Callable, typename... Policies>
EMSCRIPTEN_ALWAYS_INLINE const class_& constructor(Callable callable, Policies...) const {
using invoker = internal::RegisterClassConstructor<
typename std::conditional<std::is_same<Signature, internal::DeduceArgumentsTag>::value,
Callable,
internal::FunctionTag<Callable, Signature>>::type>;
invoker::template invoke<ClassType, Policies...>(callable);
return *this;
}
template<typename SmartPtr, typename... Args, typename... Policies>
EMSCRIPTEN_ALWAYS_INLINE const class_& smart_ptr_constructor(const char* smartPtrName, SmartPtr (*factory)(Args...), Policies...) const {
using namespace internal;
smart_ptr<SmartPtr>(smartPtrName);
typename WithPolicies<Policies...>::template ArgTypeList<SmartPtr, Args...> args;
using ReturnPolicy = typename GetReturnValuePolicy<SmartPtr, return_value_policy::take_ownership>::tag;
auto invoke = &Invoker<ReturnPolicy, SmartPtr, Args...>::invoke;
_embind_register_class_constructor(
TypeID<ClassType>::get(),
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
reinterpret_cast<GenericFunction>(factory));
return *this;
}
template<typename WrapperType, typename... ConstructorArgs, typename... Policies>
EMSCRIPTEN_ALWAYS_INLINE const class_& allow_subclass(
const char* wrapperClassName,
::emscripten::constructor<ConstructorArgs...> = ::emscripten::constructor<>(),
Policies... policies
) const {
using namespace internal;
auto cls = class_<WrapperType, base<ClassType>>(wrapperClassName)
.function("notifyOnDestruction", select_overload<void(WrapperType&)>([](WrapperType& wrapper) {
wrapper.setNotifyJSOnDestruction(true);
}))
;
return
class_function(
"implement",
&wrapped_new<WrapperType*, WrapperType, val, ConstructorArgs...>,
allow_raw_pointer<ret_val>(), nonnull<ret_val>(),
typename ShiftPolicy<Policies>::type()...)
.class_function(
"extend",
&wrapped_extend<WrapperType>)
;
}
template<typename WrapperType, typename PointerType, typename... ConstructorArgs, typename... Policies>
EMSCRIPTEN_ALWAYS_INLINE const class_& allow_subclass(
const char* wrapperClassName,
const char* pointerName,
::emscripten::constructor<ConstructorArgs...> = ::emscripten::constructor<>(),
Policies... policies
) const {
using namespace internal;
auto cls = class_<WrapperType, base<ClassType>>(wrapperClassName)
.function("notifyOnDestruction", select_overload<void(WrapperType&)>([](WrapperType& wrapper) {
wrapper.setNotifyJSOnDestruction(true);
}))
.template smart_ptr<PointerType>(pointerName)
;
return
class_function(
"implement",
&wrapped_new<PointerType, WrapperType, val, ConstructorArgs...>,
allow_raw_pointer<ret_val>(),
typename ShiftPolicy<Policies>::type()...)
.class_function(
"extend",
&wrapped_extend<WrapperType>)
;
}
template<typename Signature = internal::DeduceArgumentsTag, typename Callable, typename... Policies>
EMSCRIPTEN_ALWAYS_INLINE const class_& function(const char* methodName, Callable callable, Policies...) const {
using invoker = internal::RegisterClassMethod<
typename std::conditional<std::is_same<Signature, internal::DeduceArgumentsTag>::value,
Callable,
internal::FunctionTag<Callable, Signature>>::type>;
invoker::template invoke<ClassType, Policies...>(methodName, callable);
return *this;
}
template<typename ElementType>
EMSCRIPTEN_ALWAYS_INLINE const class_& iterable(
const char* sizeMethodName,
const char* getMethodName) const {
using namespace internal;
_embind_register_iterable(
TypeID<ClassType>::get(),
TypeID<ElementType>::get(),
sizeMethodName,
getMethodName);
return *this;
}
template<
typename FieldType,
typename... Policies,
// Prevent the template from wrongly matching the getter function
// overload.
typename = typename std::enable_if<
!std::is_function<FieldType>::value &&
std::conjunction<internal::isPolicy<Policies>...>::value>::type>
EMSCRIPTEN_ALWAYS_INLINE const class_& property(const char* fieldName, const FieldType ClassType::*field, Policies...) const {
using namespace internal;
using ReturnPolicy = typename GetReturnValuePolicy<FieldType, Policies...>::tag;
typename WithPolicies<Policies...>::template ArgTypeList<FieldType> returnType;
auto getter = &MemberAccess<ClassType, FieldType>::template getWire<ClassType, ReturnPolicy>;
_embind_register_class_property(
TypeID<ClassType>::get(),
fieldName,
returnType.getTypes()[0],
getSignature(getter),
reinterpret_cast<GenericFunction>(getter),
getContext(field),
0,
0,
0,
0);
return *this;
}
template<
typename FieldType,
typename... Policies,
// Prevent the template from wrongly matching the getter function
// overload.
typename = typename std::enable_if<
!std::is_function<FieldType>::value &&
std::conjunction<internal::isPolicy<Policies>...>::value>::type>
EMSCRIPTEN_ALWAYS_INLINE const class_& property(const char* fieldName, FieldType ClassType::*field, Policies...) const {
using namespace internal;
using ReturnPolicy = typename GetReturnValuePolicy<FieldType, Policies...>::tag;
typename WithPolicies<Policies...>::template ArgTypeList<FieldType> returnType;
auto getter = &MemberAccess<ClassType, FieldType>::template getWire<ClassType, ReturnPolicy>;
auto setter = &MemberAccess<ClassType, FieldType>::template setWire<ClassType>;
_embind_register_class_property(
TypeID<ClassType>::get(),
fieldName,
returnType.getTypes()[0],
getSignature(getter),
reinterpret_cast<GenericFunction>(getter),
getContext(field),
returnType.getTypes()[0],
getSignature(setter),
reinterpret_cast<GenericFunction>(setter),
getContext(field));
return *this;
}
template<
typename PropertyType = internal::DeduceArgumentsTag,
typename Getter,
typename... Policies,
// Prevent the template from wrongly matching the getter/setter overload
// of this function.
typename = typename std::enable_if<
std::conjunction<internal::isPolicy<Policies>...>::value>::type>
EMSCRIPTEN_ALWAYS_INLINE const class_& property(const char* fieldName, Getter getter, Policies...) const {
using namespace internal;
typedef GetterPolicy<
typename std::conditional<std::is_same<PropertyType, internal::DeduceArgumentsTag>::value,
Getter,
FunctionTag<Getter, PropertyType>>::type> GP;
using ReturnPolicy = typename GetReturnValuePolicy<typename GP::ReturnType, Policies...>::tag;
auto gter = &GP::template get<ClassType, ReturnPolicy>;
typename WithPolicies<Policies...>::template ArgTypeList<typename GP::ReturnType> returnType;
_embind_register_class_property(
TypeID<ClassType>::get(),
fieldName,
returnType.getTypes()[0],
getSignature(gter),
reinterpret_cast<GenericFunction>(gter),
GP::getContext(getter),
0,
0,
0,
0);
return *this;
}
template<
typename PropertyType = internal::DeduceArgumentsTag,
typename Getter,
typename Setter,
typename... Policies,
// Similar to the other variadic property overloads this can greedily
// match the wrong overload so we need to ensure the setter is not a
// policy argument.
typename = typename std::enable_if<!internal::isPolicy<Setter>::value>::type>
EMSCRIPTEN_ALWAYS_INLINE const class_& property(const char* fieldName, Getter getter, Setter setter, Policies...) const {
using namespace internal;
typedef GetterPolicy<
typename std::conditional<std::is_same<PropertyType, internal::DeduceArgumentsTag>::value,
Getter,
FunctionTag<Getter, PropertyType>>::type> GP;
typedef SetterPolicy<
typename std::conditional<std::is_same<PropertyType, internal::DeduceArgumentsTag>::value,
Setter,
FunctionTag<Setter, PropertyType>>::type> SP;
using ReturnPolicy = typename GetReturnValuePolicy<typename GP::ReturnType, Policies...>::tag;
auto gter = &GP::template get<ClassType, ReturnPolicy>;
auto ster = &SP::template set<ClassType>;
typename WithPolicies<Policies...>::template ArgTypeList<typename GP::ReturnType> returnType;
// XXX: This currently applies all the policies (including return value policies) to the
// setter function argument to allow pointers. Using return value policies doesn't really
// make sense on an argument, but we don't have separate argument policies yet.
typename WithPolicies<Policies...>::template ArgTypeList<typename SP::ArgumentType> argType;
_embind_register_class_property(
TypeID<ClassType>::get(),
fieldName,
returnType.getTypes()[0],
getSignature(gter),
reinterpret_cast<GenericFunction>(gter),
GP::getContext(getter),
argType.getTypes()[0],
getSignature(ster),
reinterpret_cast<GenericFunction>(ster),
SP::getContext(setter));
return *this;
}
template<typename ReturnType, typename... Args, typename... Policies>
EMSCRIPTEN_ALWAYS_INLINE const class_& class_function(const char* methodName, ReturnType (*classMethod)(Args...), Policies...) const {
using namespace internal;
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args;
using ReturnPolicy = typename GetReturnValuePolicy<ReturnType, Policies...>::tag;
auto invoke = internal::Invoker<ReturnPolicy, ReturnType, Args...>::invoke;
_embind_register_class_class_function(
TypeID<ClassType>::get(),
methodName,
args.getCount(),
args.getTypes(),
getSignature(invoke),
reinterpret_cast<GenericFunction>(invoke),
reinterpret_cast<GenericFunction>(classMethod),
isAsync<Policies...>::value,
isNonnullReturn<Policies...>::value);
return *this;
}
template<typename FieldType>
EMSCRIPTEN_ALWAYS_INLINE const class_& class_property(const char* name, const FieldType* field) const {
using namespace internal;
auto getter = &GlobalAccess<FieldType>::get;
_embind_register_class_class_property(
TypeID<ClassType>::get(),
name,
TypeID<FieldType>::get(),
field,
getSignature(getter),
reinterpret_cast<GenericFunction>(getter),
0,
0);
return *this;
}
template<typename FieldType>
EMSCRIPTEN_ALWAYS_INLINE const class_& class_property(const char* name, FieldType* field) const {
using namespace internal;
auto getter = &GlobalAccess<FieldType>::get;
auto setter = &GlobalAccess<FieldType>::set;
_embind_register_class_class_property(
TypeID<ClassType>::get(),
name,
TypeID<FieldType>::get(),
field,
getSignature(getter),
reinterpret_cast<GenericFunction>(getter),
getSignature(setter),
reinterpret_cast<GenericFunction>(setter));
return *this;
}
};
template<typename T>
void register_optional() {
// Optional types are automatically registered for some internal types so
// only run the register method once so we don't conflict with a user's
// bindings if they also register the optional type.
thread_local bool hasRun;
if (hasRun) {
return;
}
hasRun = true;
internal::_embind_register_optional(
internal::TypeID<std::optional<T>>::get(),
internal::TypeID<typename std::remove_pointer<T>::type>::get());
}
////////////////////////////////////////////////////////////////////////////////
// VECTORS
////////////////////////////////////////////////////////////////////////////////
namespace internal {
template<typename VectorType>
struct VectorAccess {
static std::optional<typename VectorType::value_type> get(
const VectorType& v,
unsigned int index
) {
if (index < v.size()) {
return v[index];
} else {
return {};
}
}
static bool set(
VectorType& v,
unsigned int index,
const typename VectorType::value_type& value
) {
v[index] = value;
return true;
}
static unsigned int size(const VectorType& v) {
return v.size();
}
static void resize(
VectorType& v,
unsigned int len,
const typename VectorType::value_type& value
) {
v.resize(len, value);
}
static void push_back(
VectorType& v,
typename VectorType::value_type&& value
) {
v.push_back(std::move(value));
}
};
} // end namespace internal
template<typename T, class Allocator=std::allocator<T>>
class_<std::vector<T, Allocator>> register_vector(const char* name) {
typedef std::vector<T, Allocator> VecType;
register_optional<T>();
using VectorElementType =
typename internal::RawPointerTransformer<T, std::is_pointer<T>::value>::type;
return class_<VecType>(name)
.template constructor<>()
.function("push_back", internal::VectorAccess<VecType>::push_back, allow_raw_pointers())
.function("resize", internal::VectorAccess<VecType>::resize, allow_raw_pointers())
.function("size", internal::VectorAccess<VecType>::size, allow_raw_pointers())
.function("get", internal::VectorAccess<VecType>::get, allow_raw_pointers())
.function("set", internal::VectorAccess<VecType>::set, allow_raw_pointers())
.template iterable<VectorElementType>("size", "get");
}
////////////////////////////////////////////////////////////////////////////////
// MAPS
////////////////////////////////////////////////////////////////////////////////
namespace internal {
template<typename MapType>
struct MapAccess {
static std::optional<typename MapType::mapped_type> get(
const MapType& m,
const typename MapType::key_type& k
) {
auto i = m.find(k);
if (i == m.end()) {
return {};
} else {
return i->second;
}
}
static void set(
MapType& m,
const typename MapType::key_type& k,
const typename MapType::mapped_type& v
) {
m[k] = v;
}
static std::vector<typename MapType::key_type> keys(
const MapType& m
) {
std::vector<typename MapType::key_type> keys;
keys.reserve(m.size());
for (const auto& pair : m) {
keys.push_back(pair.first);
}
return keys;
}
static unsigned int size(const MapType& m) {
return m.size();
}
};
} // end namespace internal
template<typename K, typename V, class Compare = std::less<K>,
class Allocator = std::allocator<std::pair<const K, V>>>
class_<std::map<K, V, Compare, Allocator>> register_map(const char* name) {
typedef std::map<K,V, Compare, Allocator> MapType;
register_optional<V>();
return class_<MapType>(name)
.template constructor<>()
.function("size", internal::MapAccess<MapType>::size)
.function("get", internal::MapAccess<MapType>::get)
.function("set", internal::MapAccess<MapType>::set)
.function("keys", internal::MapAccess<MapType>::keys)
;
}
////////////////////////////////////////////////////////////////////////////////
// ENUMS
////////////////////////////////////////////////////////////////////////////////
template<typename EnumType>
class enum_ {
public:
typedef EnumType enum_type;
enum_(const char* name, enum_value_type valueType = enum_value_type::object) {
using namespace internal;
_embind_register_enum(
internal::TypeID<EnumType>::get(),
name,
sizeof(EnumType),
std::is_signed<typename std::underlying_type<EnumType>::type>::value,
static_cast<int>(valueType));
}
enum_& value(const char* name, EnumType value) {
using namespace internal;
// TODO: there's still an issue here.
// if EnumType is an unsigned long, then JS may receive it as a signed long
static_assert(sizeof(value) <= sizeof(internal::GenericEnumValue), "enum type must fit in a GenericEnumValue");
_embind_register_enum_value(
internal::TypeID<EnumType>::get(),
name,
static_cast<internal::GenericEnumValue>(value));
return *this;
}
};
////////////////////////////////////////////////////////////////////////////////
// CONSTANTS
////////////////////////////////////////////////////////////////////////////////
namespace internal {
template<typename T> double asGenericValue(T t) {
return static_cast<double>(t);
}
template<typename T> uintptr_t asGenericValue(T* p) {
return reinterpret_cast<uintptr_t>(p);
}
}
template<typename ConstantType>
void constant(const char* name, const ConstantType& v) {
using namespace internal;
typedef BindingType<const ConstantType&> BT;
_embind_register_constant(
name,
TypeID<const ConstantType&>::get(),
static_cast<double>(asGenericValue(BT::toWireType(v, rvp::default_tag{}))));
}
template <typename T>
inline void register_type(const char* name) {
using namespace internal;
_embind_register_user_type(TypeID<T>::get(), name);
}
template <typename T>
inline void register_type(const char* name, const char* definition) {
using namespace internal;
_embind_register_user_type_definition(TypeID<T>::get(), name, definition);
}
// EMSCRIPTEN_BINDINGS creates a static struct to initialize the binding which
// will get included in the program if the translation unit in which it is
// defined gets linked into the program. Using a C++ constructor here ensures it
// occurs after any other C++ constructors in this file, which is not true for
// __attribute__((constructor)) (they run before C++ constructors in the same
// file).
#define EMSCRIPTEN_BINDINGS(name) \
static void embind_init_##name(); \
static struct EmBindInit_##name : emscripten::internal::InitFunc { \
EmBindInit_##name() : InitFunc(embind_init_##name) {} \
} EmBindInit_##name##_instance; \
static void embind_init_##name()
} // end namespace emscripten