From e403b510d0de74ac7e62defeb1e80eff84b956e2 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Mon, 12 May 2025 12:38:58 -0700 Subject: [PATCH] Support bridging for Class methods return types (#51223) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/51223 Changelog: [General][Added] - Added support for bridging Class methods return types Previously, this wouldn't work, unless you define your C++ implementation of the TM to have primitive return type that can be converted to JavaScript's type. Reviewed By: javache Differential Revision: D74478572 fbshipit-source-id: 75c7f589559394704446be1ebac245d38a5c4b2b --- .../ReactCommon/react/bridging/Class.h | 3 +- .../react/bridging/tests/ClassTest.cpp | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/packages/react-native/ReactCommon/react/bridging/Class.h b/packages/react-native/ReactCommon/react/bridging/Class.h index 61fa82e338c..0d0fcd49e8b 100644 --- a/packages/react-native/ReactCommon/react/bridging/Class.h +++ b/packages/react-native/ReactCommon/react/bridging/Class.h @@ -41,7 +41,7 @@ T callFromJs( rt, fromJs(rt, std::forward(args), jsInvoker)...); return jsi::Value(); - } else if constexpr (is_jsi_v) { + } else if constexpr (is_jsi_v || supportsToJs) { static_assert(supportsToJs, "Incompatible return type"); return toJs( @@ -49,7 +49,6 @@ T callFromJs( (instance->*method)( rt, fromJs(rt, std::forward(args), jsInvoker)...), jsInvoker); - } else if constexpr (is_optional_jsi_v) { static_assert( is_optional_v diff --git a/packages/react-native/ReactCommon/react/bridging/tests/ClassTest.cpp b/packages/react-native/ReactCommon/react/bridging/tests/ClassTest.cpp index dfcf9f29ec5..f01b9f5c07d 100644 --- a/packages/react-native/ReactCommon/react/bridging/tests/ClassTest.cpp +++ b/packages/react-native/ReactCommon/react/bridging/tests/ClassTest.cpp @@ -92,4 +92,62 @@ TEST_F(BridgingTest, callFromJsTest) { EXPECT_TRUE(called); } +struct MethodReturnTypeCastingTestObject { + public: + explicit MethodReturnTypeCastingTestObject(int value) : value_(value) {} + + int toInteger() const { + return value_; + } + + private: + int value_; +}; + +template <> +struct Bridging { + static MethodReturnTypeCastingTestObject fromJs( + jsi::Runtime& /*rt*/, + const jsi::Value& value) { + return MethodReturnTypeCastingTestObject( + static_cast(value.asNumber())); + } + + static int toJs( + jsi::Runtime& /*rt*/, + const MethodReturnTypeCastingTestObject& value) { + return value.toInteger(); + } +}; + +struct MethodReturnTypeCastingTestClass { + explicit MethodReturnTypeCastingTestClass( + std::shared_ptr invoker) + : invoker_(std::move(invoker)) {} + + // This is the key, return type is not a primitive, but an object with defined + // bridging template. + MethodReturnTypeCastingTestObject + add(jsi::Runtime& /*unused*/, int a, int b) { + return MethodReturnTypeCastingTestObject(a + b); + } + + private: + std::shared_ptr invoker_; +}; + +TEST_F(BridgingTest, methodReturnTypeCastingTest) { + auto instance = MethodReturnTypeCastingTestClass(invoker); + + EXPECT_EQ( + 2, + bridging::callFromJs( + rt, + &MethodReturnTypeCastingTestClass::add, + invoker, + &instance, + 1, + 1)); +} + } // namespace facebook::react