Workaround to pass C++ references to JS (equivalent of return_value_policy
for val::call()
)?
#23271
Replies: 2 comments
-
Btw, I've actually done something already for converting C++ types that are "strong type" aliases to other types, particularly to fundamental types. In this case, I treat them as values. For example, I have a /*!
* Defines a binding for a type that can be casted to an underlying basic type
* (e.g. int, std::string, etc.) that has a direct JS representation.
*
* Requires that static_cast works in both directions.
*/
#define BNZ_EMBIND_TYPE_ALIAS(cpp_type_, base_type_) \
namespace emscripten::internal { \
template <> \
struct BindingType<cpp_type_> \
{ \
using cpp_type = cpp_type_; \
using base_type = base_type_; \
using base_binding = BindingType<base_type>; \
using WireType = base_binding::WireType; \
static WireType toWireType(const cpp_type& v, rvp::default_tag tag) \
{ \
return base_binding::toWireType(static_cast<base_type>(v), tag); \
} \
static cpp_type fromWireType(WireType v) \
{ \
return static_cast<cpp_type>(base_binding::fromWireType(v)); \
} \
}; \
} // namespace emscripten::internal
/*!
* Registers a type alias that has been defined with BNZ_EMBIND_TYPE_ALIAS.
*/
template <typename T>
void register_type_alias(const char* name)
{
using namespace emscripten::internal;
using base_t = BindingType<T>::base_type; // Remember BNZ_EMBIND_TYPE_ALIAS!
if constexpr (std::is_integral_v<base_t>) {
if (sizeof(base_t) < 8) {
_embind_register_integer(TypeID<T>::get(),
name,
sizeof(base_t),
std::numeric_limits<base_t>::min(),
std::numeric_limits<base_t>::max());
} else {
_embind_register_bigint(TypeID<T>::get(),
name,
sizeof(base_t),
std::numeric_limits<base_t>::min(),
std::numeric_limits<base_t>::max());
}
} else if constexpr (std::is_floating_point_v<base_t>) {
_embind_register_float(TypeID<T>::get(), name, sizeof(base_t));
} else if constexpr (detail::is_string_type<base_t>::value) {
using char_t = base_t::value_type;
if (sizeof(char_t) == 1) {
_embind_register_std_string(TypeID<T>::get(), name);
} else {
_embind_register_std_wstring(
TypeID<T>::get(), sizeof(char_t), name);
}
} else {
BNZ_LOG(warn, "failing to register type: ", name);
}
} That then I can use like this: BNZ_EMBIND_TYPE_ALIAS(bnz::uuid, std::string);
EMSCRIPTEN_BINDINGS(uuid)
{
register_type_alias<bnz::uuid>("UUID");
} I'm just not familiar enough yet with the interactions between the wire machinery and |
Beta Was this translation helpful? Give feedback.
-
Another idea: if a class is to be only used by reference, I can use |
Beta Was this translation helpful? Give feedback.
-
As mentioned here: #22402 passing a C++
class_
to a JS function always makes a copy that needs to be released withdelete()
.I am designing my API's to avoid
delete()
as much as possible by using a combination of references and value types.One major hurdle I am finding is the lack of an official mechanism to pass references to JS when using something like
val::call()
oroperator()
. Is there any way any of you can think of doing this? I'm ok with using black magic (e.g.internals::BindingType
and so on, I am already using some of that for things like mapping strong type aliases).One workaround I can think of is something like this:
This has two main disadvantages:
.v
to access the value...reference_wrapper
, which may have some performance penalties. Also I'm just hoping that this is not a leak becausestd::reference_wrapper
doesn't do anything in the destructor, but...But... maybe I'm after something here? What about doing something with the
std::reference_wrapper
BindingType
and registration so that it operates as a proxy for passing around references that work like the underlying type? Any ideas @brendandahl?Beta Was this translation helpful? Give feedback.
All reactions