Skip to content

Commit 9ce7020

Browse files
authored
embind: Support generating custom TS for val types. (#19999)
This allows better definitions of C++ interfaces for TypesScript users when a C++ function takes `val` (JS values) arguments.
1 parent abada95 commit 9ce7020

File tree

7 files changed

+51
-2
lines changed

7 files changed

+51
-2
lines changed

src/embind/embind.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,11 @@ var LibraryEmbind = {
680680
});
681681
},
682682

683+
_embind_register_user_type__deps: ['_embind_register_emval'],
684+
_embind_register_user_type: (rawType, name) => {
685+
__embind_register_emval(rawType, name);
686+
},
687+
683688
_embind_register_memory_view__deps: ['$readLatin1String', '$registerType'],
684689
_embind_register_memory_view: (rawType, dataTypeIndex, name) => {
685690
var typeMapping = [

src/embind/embind_ts.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ var LibraryEmbind = {
2525
this.type = type;
2626
}
2727
},
28+
$UserType: class UserType {
29+
constructor(typeId, name) {
30+
this.typeId = typeId;
31+
this.name = name;
32+
}
33+
},
2834
$FunctionDefinition: class FunctionDefinition {
2935
constructor(name, returnType, argumentTypes, thisType = null) {
3036
this.name = name;
@@ -316,6 +322,11 @@ var LibraryEmbind = {
316322
_embind_register_emval: (rawType, name) => {
317323
registerPrimitiveType(rawType, name);
318324
},
325+
_embind_register_user_type__deps: ['$registerType', '$readLatin1String', '$UserType'],
326+
_embind_register_user_type: (rawType, name) => {
327+
name = readLatin1String(name);
328+
registerType(rawType, new UserType(rawType, name));
329+
},
319330
_embind_register_memory_view: (rawType, dataTypeIndex, name) => {
320331
// TODO
321332
},

src/library_sigs.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ sigs = {
307307
_embind_register_smart_ptr__sig: 'vpppipppppppp',
308308
_embind_register_std_string__sig: 'vpp',
309309
_embind_register_std_wstring__sig: 'vppp',
310+
_embind_register_user_type__sig: 'vpp',
310311
_embind_register_value_array__sig: 'vpppppp',
311312
_embind_register_value_array_element__sig: 'vppppppppp',
312313
_embind_register_value_object__sig: 'vpppppp',

system/include/emscripten/bind.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ void _embind_register_constant(
249249
TYPEID constantType,
250250
double value);
251251

252+
void _embind_register_user_type(
253+
TYPEID type,
254+
const char* typeName);
255+
252256
// Register an InitFunc in the global linked list of init functions.
253257
void _embind_register_bindings(struct InitFunc* f);
254258

@@ -2021,6 +2025,12 @@ void constant(const char* name, const ConstantType& v) {
20212025
static_cast<double>(asGenericValue(BT::toWireType(v))));
20222026
}
20232027

2028+
template <typename T>
2029+
inline void register_type(const char* name) {
2030+
using namespace internal;
2031+
_embind_register_user_type(TypeID<T>::get(), name);
2032+
}
2033+
20242034
// EMSCRIPTEN_BINDINGS creates a static struct to initialize the binding which
20252035
// will get included in the program if the translation unit in which it is
20262036
// defined gets linked into the program. Using a C++ constructor here ensures it

system/include/emscripten/val.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <emscripten/wire.h>
1818
#include <cstdint> // uintptr_t
1919
#include <vector>
20+
#include <type_traits>
2021

2122

2223
namespace emscripten {
@@ -625,10 +626,18 @@ class val {
625626
friend struct internal::BindingType<val>;
626627
};
627628

629+
// Declare a custom type that can be used in conjuction with
630+
// emscripten::register_type to emit custom TypeScript defintions for val types.
631+
#define EMSCRIPTEN_DECLARE_VAL_TYPE(name) \
632+
struct name : public val { \
633+
name(val const &other) : val(other) {} \
634+
};
635+
628636
namespace internal {
629637

630-
template<>
631-
struct BindingType<val> {
638+
template<typename T>
639+
struct BindingType<T, typename std::enable_if<std::is_base_of<val, T>::value &&
640+
!std::is_const<T>::value>::type> {
632641
typedef EM_VAL WireType;
633642
static WireType toWireType(const val& v) {
634643
_emval_incref(v.handle);

test/other/embind_tsgen.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ int smart_ptr_function(std::shared_ptr<ClassWithSmartPtrConstructor>) {
7070
return 0;
7171
}
7272

73+
EMSCRIPTEN_DECLARE_VAL_TYPE(CallbackType);
74+
75+
int function_with_callback_param(CallbackType ct) {
76+
ct(val("hello"));
77+
return 0;
78+
}
79+
7380
int global_fn(int, int) { return 0; }
7481

7582
class BaseClass {
@@ -150,6 +157,11 @@ EMSCRIPTEN_BINDINGS(Test) {
150157
function("smart_ptr_function", &smart_ptr_function);
151158
function("smart_ptr_function_with_params(foo)", &smart_ptr_function);
152159

160+
function("function_with_callback_param",
161+
&function_with_callback_param);
162+
163+
register_type<CallbackType>("(message: string) => void");
164+
153165
class_<BaseClass>("BaseClass").function("fn", &BaseClass::fn);
154166

155167
class_<DerivedClass, base<BaseClass>>("DerivedClass")

test/other/embind_tsgen.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,5 @@ export interface MainModule {
7878
global_fn(_0: number, _1: number): number;
7979
smart_ptr_function(_0: ClassWithSmartPtrConstructor): number;
8080
smart_ptr_function_with_params(foo: ClassWithSmartPtrConstructor): number;
81+
function_with_callback_param(_0: (message: string) => void): number;
8182
}

0 commit comments

Comments
 (0)