|
15 | 15 | #include <array>
|
16 | 16 | #include <climits>
|
17 | 17 | #include <emscripten/wire.h>
|
| 18 | +#include <functional> |
18 | 19 | #include <cstdint> // uintptr_t
|
19 | 20 | #include <vector>
|
20 | 21 | #include <type_traits>
|
|
24 | 25 | #include <exception>
|
25 | 26 | #include <variant>
|
26 | 27 | #endif
|
| 28 | +#if __has_feature(cxx_rtti) |
| 29 | +#include <typeinfo> |
| 30 | +#endif |
27 | 31 |
|
28 | 32 | namespace emscripten {
|
29 | 33 |
|
@@ -341,6 +345,14 @@ class EMBIND_VISIBILITY_DEFAULT val {
|
341 | 345 | return val(internal::_emval_get_module_property(name));
|
342 | 346 | }
|
343 | 347 |
|
| 348 | +#if __has_feature(cxx_rtti) |
| 349 | + // Create a `val` from a user-defined dynamic `type` that is ABI-compatible with static type `T`: |
| 350 | + template<typename T> |
| 351 | + static val dyn(const std::type_info& type, T&& value) { |
| 352 | + return internalDynCast<val>(internal::TypeID<val>::get(), &type, nullptr, std::forward<T>(value), std::identity()); |
| 353 | + } |
| 354 | +#endif |
| 355 | + |
344 | 356 | template<typename T, typename... Policies>
|
345 | 357 | explicit val(T&& value, Policies...) {
|
346 | 358 | using namespace internal;
|
@@ -516,6 +528,14 @@ class EMBIND_VISIBILITY_DEFAULT val {
|
516 | 528 | return internalCall<EM_INVOKER_KIND::CAST, WithPolicies<Policies...>, T>(as_handle(), nullptr, *this);
|
517 | 529 | }
|
518 | 530 |
|
| 531 | +#if __has_feature(cxx_rtti) |
| 532 | + // Retrieve a user-defined dynamic `type` that is ABI-compatible with static type `T`: |
| 533 | + template<typename T, typename TransformFn> |
| 534 | + auto dyn_as(const std::type_info& type, TransformFn transform) const { |
| 535 | + return internalDynCast<T>(&type, internal::TypeID<val>::get(), as_handle(), *this, transform); |
| 536 | + } |
| 537 | +#endif |
| 538 | + |
519 | 539 | // Prefer calling val::typeOf() over val::typeof(), since this form works in both C++11 and GNU++11 build modes. "typeof" is a reserved word in GNU++11 extensions.
|
520 | 540 | val typeOf() const {
|
521 | 541 | return val(internal::_emval_typeof(as_handle()));
|
@@ -573,42 +593,68 @@ class EMBIND_VISIBILITY_DEFAULT val {
|
573 | 593 | template<typename WrapperType>
|
574 | 594 | friend val internal::wrapped_extend(const std::string& , const val& );
|
575 | 595 |
|
576 |
| - template<internal::EM_INVOKER_KIND Kind, typename Policy, typename Ret, typename... Args> |
577 |
| - static Ret internalCall(EM_VAL handle, const char *methodName, Args&&... args) { |
578 |
| - static_assert(!std::is_lvalue_reference<Ret>::value, |
579 |
| - "Cannot create a lvalue reference out of a JS value."); |
580 |
| - |
| 596 | + template<typename Ret, typename... Args> |
| 597 | + static auto internalDoCall(internal::EM_INVOKER caller, EM_VAL handle, const char* methodName, internal::EM_DESTRUCTORS* destructors, Args&&... args) { |
581 | 598 | using namespace internal;
|
582 | 599 |
|
583 | 600 | using RetWire = BindingType<Ret>::WireType;
|
584 | 601 |
|
585 |
| - static constexpr typename Policy::template ArgTypeList<Ret, Args...> argTypes; |
586 |
| - thread_local EM_INVOKER mc = _emval_create_invoker(argTypes.getCount(), argTypes.getTypes(), Kind); |
587 |
| - |
588 | 602 | WireTypePack<Args...> argv(std::forward<Args>(args)...);
|
589 |
| - EM_DESTRUCTORS destructors = nullptr; |
590 | 603 |
|
591 | 604 | RetWire result;
|
592 | 605 | if constexpr (std::is_integral<RetWire>::value && sizeof(RetWire) == 8) {
|
593 | 606 | // 64-bit integers can't go through "generic wire type" because double and int64 have different ABI.
|
594 | 607 | result = static_cast<RetWire>(_emval_invoke_i64(
|
595 |
| - mc, |
| 608 | + caller, |
596 | 609 | handle,
|
597 | 610 | methodName,
|
598 |
| - &destructors, |
| 611 | + destructors, |
599 | 612 | argv));
|
600 | 613 | } else {
|
601 | 614 | result = GenericWireTypeConverter<RetWire>::from(_emval_invoke(
|
602 |
| - mc, |
| 615 | + caller, |
603 | 616 | handle,
|
604 | 617 | methodName,
|
605 |
| - &destructors, |
| 618 | + destructors, |
606 | 619 | argv));
|
607 | 620 | }
|
| 621 | + return result; |
| 622 | + } |
| 623 | + |
| 624 | + template<internal::EM_INVOKER_KIND Kind, typename Policy, typename Ret, typename... Args> |
| 625 | + static Ret internalCall(EM_VAL handle, const char *methodName, Args&&... args) { |
| 626 | + static_assert(!std::is_lvalue_reference<Ret>::value, |
| 627 | + "Cannot create a lvalue reference out of a JS value."); |
| 628 | + |
| 629 | + using namespace internal; |
| 630 | + |
| 631 | + static constexpr typename Policy::template ArgTypeList<Ret, Args...> argTypes; |
| 632 | + thread_local EM_INVOKER mc = _emval_create_invoker(argTypes.getCount(), argTypes.getTypes(), Kind); |
| 633 | + |
| 634 | + EM_DESTRUCTORS destructors = nullptr; |
| 635 | + |
| 636 | + auto result = internalDoCall<Ret>(mc, handle, methodName, &destructors, std::forward<Args>(args)...); |
608 | 637 | DestructorsRunner rd(destructors);
|
609 | 638 | return BindingType<Ret>::fromWireType(result);
|
610 | 639 | }
|
611 | 640 |
|
| 641 | + template<typename Ret, typename Arg, typename TransformFn> |
| 642 | + static auto internalDynCast(internal::TYPEID retType, internal::TYPEID argType, EM_VAL handle, Arg&& arg, TransformFn transform) { |
| 643 | + static_assert(!std::is_lvalue_reference<Ret>::value, |
| 644 | + "Cannot create a lvalue reference out of a JS value."); |
| 645 | + |
| 646 | + using namespace internal; |
| 647 | + |
| 648 | + TYPEID const argTypes[2] { retType, argType }; |
| 649 | + EM_INVOKER mc = _emval_create_invoker(2, argTypes, EM_INVOKER_KIND::CAST); |
| 650 | + |
| 651 | + EM_DESTRUCTORS destructors = nullptr; |
| 652 | + |
| 653 | + auto result = internalDoCall<Ret>(mc, handle, nullptr, &destructors, std::forward<Arg>(arg)); |
| 654 | + DestructorsRunner rd(destructors); |
| 655 | + return transform(BindingType<Ret>::fromWireType(result)); |
| 656 | + } |
| 657 | + |
612 | 658 | template<typename T>
|
613 | 659 | val val_ref(const T& v) const {
|
614 | 660 | return val(v);
|
|
0 commit comments