From d86eb46b0fcccaec896a18ff9f2952d0e1c4ae19 Mon Sep 17 00:00:00 2001 From: Genki Kondo Date: Thu, 4 May 2023 09:21:33 -0700 Subject: [PATCH] Add JSI<->C++ bridging conversion for folly::dynamic (#37237) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/37237 Enables bridging conversions to/from jsi::Value and folly::dynamic. Changelog: [Internal] - Add JSI<->C++ bridging conversion for folly::dynamic Reviewed By: javache Differential Revision: D45544843 fbshipit-source-id: 8c905a03bb45fd786262f2686846bd097fdf5bc2 --- .../ReactCommon/react/bridging/Bridging.h | 1 + .../ReactCommon/react/bridging/Dynamic.h | 26 ++++++ .../react/bridging/tests/BridgingTest.cpp | 86 +++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 packages/react-native/ReactCommon/react/bridging/Dynamic.h diff --git a/packages/react-native/ReactCommon/react/bridging/Bridging.h b/packages/react-native/ReactCommon/react/bridging/Bridging.h index 26cf99b5208302..b8a02290d1aee1 100644 --- a/packages/react-native/ReactCommon/react/bridging/Bridging.h +++ b/packages/react-native/ReactCommon/react/bridging/Bridging.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/packages/react-native/ReactCommon/react/bridging/Dynamic.h b/packages/react-native/ReactCommon/react/bridging/Dynamic.h new file mode 100644 index 00000000000000..be9555b49d594c --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridging/Dynamic.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook::react { + +template <> +struct Bridging { + static folly::dynamic fromJs(jsi::Runtime &rt, const jsi::Value &value) { + return jsi::dynamicFromValue(rt, value); + } + + static jsi::Value toJs(jsi::Runtime &rt, const folly::dynamic &value) { + return jsi::valueFromDynamic(rt, value); + } +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp b/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp index 995bce42e62d2a..6d739619f90df5 100644 --- a/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp +++ b/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp @@ -532,4 +532,90 @@ TEST_F(BridgingTest, supportTest) { EXPECT_FALSE((bridging::supportsToJs, jsi::Function>)); } +TEST_F(BridgingTest, dynamicTest) { + // Null + auto nullFromJsResult = + bridging::fromJs(rt, jsi::Value::null(), invoker); + EXPECT_TRUE(nullFromJsResult.isNull()); + + auto nullToJsResult = bridging::toJs(rt, nullptr, invoker); + EXPECT_TRUE(nullToJsResult.isNull()); + + // Boolean + auto booleanFromJsResult = + bridging::fromJs(rt, jsi::Value(true), invoker); + EXPECT_TRUE(booleanFromJsResult.isBool()); + EXPECT_TRUE(booleanFromJsResult.asBool()); + + auto booleanToJsResult = bridging::toJs(rt, true, invoker); + EXPECT_TRUE(booleanToJsResult.isBool()); + EXPECT_TRUE(booleanToJsResult.asBool()); + + // Number + auto numberFromJsResult = + bridging::fromJs(rt, jsi::Value(1.2), invoker); + EXPECT_TRUE(numberFromJsResult.isNumber()); + EXPECT_DOUBLE_EQ(1.2, numberFromJsResult.asDouble()); + + auto numberToJsResult = bridging::toJs(rt, 1.2, invoker); + EXPECT_TRUE(numberToJsResult.isNumber()); + EXPECT_DOUBLE_EQ(1.2, numberToJsResult.asNumber()); + + // String + auto stringFromJsResult = bridging::fromJs( + rt, jsi::Value(jsi::String::createFromAscii(rt, "hello")), invoker); + EXPECT_TRUE(stringFromJsResult.isString()); + EXPECT_EQ("hello"s, stringFromJsResult.asString()); + + auto stringToJsResult = bridging::toJs(rt, "hello", invoker); + EXPECT_TRUE(stringToJsResult.isString()); + EXPECT_EQ("hello"s, stringToJsResult.asString(rt).utf8(rt)); + + // Array + auto arrayFromJsResult = bridging::fromJs( + rt, + jsi::Value(jsi::Array::createWithElements(rt, "foo", "bar")), + invoker); + EXPECT_TRUE(arrayFromJsResult.isArray()); + EXPECT_EQ(2, arrayFromJsResult.size()); + EXPECT_EQ("foo"s, arrayFromJsResult[0].asString()); + EXPECT_EQ("bar"s, arrayFromJsResult[1].asString()); + + auto arrayToJsResult = bridging::toJs( + rt, folly::dynamic::array("foo", "bar"), invoker); + EXPECT_TRUE(arrayToJsResult.isObject()); + EXPECT_TRUE(arrayToJsResult.asObject(rt).isArray(rt)); + auto arrayToJsResultArray = arrayToJsResult.asObject(rt).asArray(rt); + EXPECT_EQ(2, arrayToJsResultArray.size(rt)); + EXPECT_EQ( + "foo"s, + arrayToJsResultArray.getValueAtIndex(rt, 0).asString(rt).utf8(rt)); + EXPECT_EQ( + "bar"s, + arrayToJsResultArray.getValueAtIndex(rt, 1).asString(rt).utf8(rt)); + + // Object + auto jsiObject = jsi::Object(rt); + jsiObject.setProperty(rt, "foo", "bar"); + auto objectFromJsResult = bridging::fromJs( + rt, jsi::Value(std::move(jsiObject)), invoker); + + EXPECT_TRUE(objectFromJsResult.isObject()); + EXPECT_EQ(1, objectFromJsResult.size()); + EXPECT_EQ("bar"s, objectFromJsResult["foo"].asString()); + + auto objectToJsResult = bridging::toJs( + rt, folly::dynamic::object("foo", "bar"), invoker); + EXPECT_TRUE(objectToJsResult.isObject()); + auto objectToJsResultObject = objectToJsResult.asObject(rt); + EXPECT_EQ( + "bar"s, + objectToJsResultObject.getProperty(rt, "foo").asString(rt).utf8(rt)); + + // Undefined + auto undefinedFromJsResult = + bridging::fromJs(rt, jsi::Value::undefined(), invoker); + EXPECT_TRUE(undefinedFromJsResult.isNull()); +} + } // namespace facebook::react