Skip to content

Commit 100a78a

Browse files
committed
embind: Use optional return type for vector and maps.
This helps create better TypeScript definitions for what is actually returned.
1 parent c4740bc commit 100a78a

File tree

3 files changed

+61
-9
lines changed

3 files changed

+61
-9
lines changed

system/include/emscripten/bind.h

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,6 +1875,21 @@ class class_ {
18751875
}
18761876
};
18771877

1878+
#if __cplusplus >= 201703L
1879+
template<typename T>
1880+
void register_optional() {
1881+
// Optional types are automatically registered for some internal types so
1882+
// only run the register method once so we don't conflict with a user's
1883+
// bindings if they also register the optional type.
1884+
static bool hasRun;
1885+
if (hasRun) {
1886+
return;
1887+
}
1888+
hasRun = true;
1889+
internal::_embind_register_optional(internal::TypeID<std::optional<T>>::get(), internal::TypeID<T>::get());
1890+
}
1891+
#endif
1892+
18781893
////////////////////////////////////////////////////////////////////////////////
18791894
// VECTORS
18801895
////////////////////////////////////////////////////////////////////////////////
@@ -1883,6 +1898,18 @@ namespace internal {
18831898

18841899
template<typename VectorType>
18851900
struct VectorAccess {
1901+
#if __cplusplus >= 201703L
1902+
static std::optional<typename VectorType::value_type> get(
1903+
const VectorType& v,
1904+
typename VectorType::size_type index
1905+
) {
1906+
if (index < v.size()) {
1907+
return v[index];
1908+
} else {
1909+
return {};
1910+
}
1911+
}
1912+
#else
18861913
static val get(
18871914
const VectorType& v,
18881915
typename VectorType::size_type index
@@ -1893,6 +1920,7 @@ struct VectorAccess {
18931920
return val::undefined();
18941921
}
18951922
}
1923+
#endif
18961924

18971925
static bool set(
18981926
VectorType& v,
@@ -1909,6 +1937,9 @@ struct VectorAccess {
19091937
template<typename T>
19101938
class_<std::vector<T>> register_vector(const char* name) {
19111939
typedef std::vector<T> VecType;
1940+
#if __cplusplus >= 201703L
1941+
register_optional<T>();
1942+
#endif
19121943

19131944
void (VecType::*push_back)(const T&) = &VecType::push_back;
19141945
void (VecType::*resize)(const size_t, const T&) = &VecType::resize;
@@ -1923,13 +1954,6 @@ class_<std::vector<T>> register_vector(const char* name) {
19231954
;
19241955
}
19251956

1926-
#if __cplusplus >= 201703L
1927-
template<typename T>
1928-
void register_optional() {
1929-
internal::_embind_register_optional(internal::TypeID<std::optional<T>>::get(), internal::TypeID<T>::get());
1930-
}
1931-
#endif
1932-
19331957
////////////////////////////////////////////////////////////////////////////////
19341958
// MAPS
19351959
////////////////////////////////////////////////////////////////////////////////
@@ -1938,6 +1962,19 @@ namespace internal {
19381962

19391963
template<typename MapType>
19401964
struct MapAccess {
1965+
#if __cplusplus >= 201703L
1966+
static std::optional<typename MapType::mapped_type> get(
1967+
const MapType& m,
1968+
const typename MapType::key_type& k
1969+
) {
1970+
auto i = m.find(k);
1971+
if (i == m.end()) {
1972+
return {};
1973+
} else {
1974+
return i->second;
1975+
}
1976+
}
1977+
#else
19411978
static val get(
19421979
const MapType& m,
19431980
const typename MapType::key_type& k
@@ -1949,6 +1986,7 @@ struct MapAccess {
19491986
return val(i->second);
19501987
}
19511988
}
1989+
#endif
19521990

19531991
static void set(
19541992
MapType& m,
@@ -1975,6 +2013,9 @@ struct MapAccess {
19752013
template<typename K, typename V>
19762014
class_<std::map<K, V>> register_map(const char* name) {
19772015
typedef std::map<K,V> MapType;
2016+
#if __cplusplus >= 201703L
2017+
register_optional<V>();
2018+
#endif
19782019

19792020
size_t (MapType::*size)() const = &MapType::size;
19802021
return class_<MapType>(name)

test/other/embind_tsgen.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ EMSCRIPTEN_BINDINGS(Test) {
165165

166166
register_vector<int>("IntVec");
167167

168+
register_map<int, int>("MapIntInt");
169+
168170
class_<Foo>("Foo").function("process", &Foo::process);
169171

170172
function("global_fn", &global_fn);

test/other/embind_tsgen.d.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,16 @@ export interface IntVec {
2828
push_back(_0: number): void;
2929
resize(_0: number, _1: number): void;
3030
size(): number;
31+
get(_0: number): number | undefined;
3132
set(_0: number, _1: number): boolean;
32-
get(_0: number): any;
33+
delete(): void;
34+
}
35+
36+
export interface MapIntInt {
37+
keys(): IntVec;
38+
get(_0: number): number | undefined;
39+
set(_0: number, _1: number): void;
40+
size(): number;
3341
delete(): void;
3442
}
3543

@@ -79,6 +87,7 @@ export interface MainModule {
7987
EmptyEnum: {};
8088
enum_returning_fn(): Bar;
8189
IntVec: {new(): IntVec};
90+
MapIntInt: {new(): MapIntInt};
8291
Foo: {};
8392
ClassWithConstructor: {new(_0: number, _1: ValArr): ClassWithConstructor};
8493
ClassWithTwoConstructors: {new(): ClassWithTwoConstructors; new(_0: number): ClassWithTwoConstructors};
@@ -87,8 +96,8 @@ export interface MainModule {
8796
DerivedClass: {};
8897
a_bool: boolean;
8998
an_int: number;
90-
global_fn(_0: number, _1: number): number;
9199
optional_test(_0: Foo | undefined): number | undefined;
100+
global_fn(_0: number, _1: number): number;
92101
smart_ptr_function(_0: ClassWithSmartPtrConstructor): number;
93102
smart_ptr_function_with_params(foo: ClassWithSmartPtrConstructor): number;
94103
function_with_callback_param(_0: (message: string) => void): number;

0 commit comments

Comments
 (0)