mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Support optional types for C++ TurboModules
Summary: Update C++ TurboModule codegen to wrap nullable types in `std::optional` whereas before the conversion would cause a crash. Changelog: Internal Reviewed By: mdvacca, nlutsenko Differential Revision: D35299708 fbshipit-source-id: 7daa50fe8b16879c5b3a55a633aa3f724dc5be30
This commit is contained in:
committed by
Facebook GitHub Bot
parent
370f1ca0cd
commit
6e0fa5f15e
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <jsi/jsi.h>
|
||||
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace facebook::react::bridging {
|
||||
@@ -114,11 +115,31 @@ struct Converter<jsi::Object> : public ConverterBase<jsi::Object> {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Converter<std::optional<T>> : public ConverterBase<jsi::Value> {
|
||||
Converter(jsi::Runtime &rt, std::optional<T> value)
|
||||
: ConverterBase(rt, value ? std::move(*value) : jsi::Value::null()) {}
|
||||
|
||||
operator std::optional<T>() && {
|
||||
if (value_.isNull() || value_.isUndefined()) {
|
||||
return {};
|
||||
}
|
||||
return std::move(value_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::enable_if_t<is_jsi_v<T>, int> = 0>
|
||||
auto convert(jsi::Runtime &rt, T &&value) {
|
||||
return Converter<T>(rt, std::forward<T>(value));
|
||||
}
|
||||
|
||||
template <
|
||||
typename T,
|
||||
std::enable_if_t<is_jsi_v<T> || std::is_scalar_v<T>, int> = 0>
|
||||
auto convert(jsi::Runtime &rt, std::optional<T> value) {
|
||||
return Converter<std::optional<T>>(rt, std::move(value));
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_scalar_v<T>, int> = 0>
|
||||
auto convert(jsi::Runtime &rt, T &&value) {
|
||||
return value;
|
||||
|
||||
@@ -41,6 +41,17 @@ struct Bridging<std::optional<T>> {
|
||||
return bridging::fromJs<T>(rt, value, jsInvoker);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static std::optional<T> fromJs(
|
||||
jsi::Runtime &rt,
|
||||
const std::optional<U> &value,
|
||||
const std::shared_ptr<CallInvoker> &jsInvoker) {
|
||||
if (value) {
|
||||
return bridging::fromJs<T>(rt, *value, jsInvoker);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static jsi::Value toJs(
|
||||
jsi::Runtime &rt,
|
||||
const std::optional<T> &value,
|
||||
|
||||
@@ -273,6 +273,16 @@ TEST_F(BridgingTest, promiseTest) {
|
||||
TEST_F(BridgingTest, optionalTest) {
|
||||
EXPECT_EQ(
|
||||
1, bridging::fromJs<std::optional<int>>(rt, jsi::Value(1), invoker));
|
||||
EXPECT_EQ(
|
||||
1,
|
||||
bridging::fromJs<std::optional<int>>(
|
||||
rt, std::make_optional(jsi::Value(1)), invoker));
|
||||
EXPECT_EQ(
|
||||
"hi"s,
|
||||
bridging::fromJs<std::optional<std::string>>(
|
||||
rt,
|
||||
std::make_optional(jsi::String::createFromAscii(rt, "hi")),
|
||||
invoker));
|
||||
EXPECT_FALSE(
|
||||
bridging::fromJs<std::optional<int>>(rt, jsi::Value::undefined(), invoker)
|
||||
.has_value());
|
||||
|
||||
@@ -105,19 +105,26 @@ function serializeArg(
|
||||
index: number,
|
||||
resolveAlias: AliasResolver,
|
||||
): string {
|
||||
function wrap(suffix) {
|
||||
return `args[${index}]${suffix}`;
|
||||
}
|
||||
const {typeAnnotation: nullableTypeAnnotation} = arg;
|
||||
const [typeAnnotation] = unwrapNullable<NativeModuleParamTypeAnnotation>(
|
||||
nullableTypeAnnotation,
|
||||
);
|
||||
const [typeAnnotation, nullable] =
|
||||
unwrapNullable<NativeModuleParamTypeAnnotation>(nullableTypeAnnotation);
|
||||
|
||||
let realTypeAnnotation = typeAnnotation;
|
||||
if (realTypeAnnotation.type === 'TypeAliasTypeAnnotation') {
|
||||
realTypeAnnotation = resolveAlias(realTypeAnnotation.name);
|
||||
}
|
||||
|
||||
function wrap(suffix) {
|
||||
const val = `args[${index}]`;
|
||||
const expression = `${val}${suffix}`;
|
||||
|
||||
if (nullable) {
|
||||
return `${val}.isNull() || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`;
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
switch (realTypeAnnotation.type) {
|
||||
case 'ReservedTypeAnnotation':
|
||||
switch (realTypeAnnotation.name) {
|
||||
|
||||
@@ -110,19 +110,24 @@ function translatePrimitiveJSTypeToCpp(
|
||||
createErrorMessage: (typeName: string) => string,
|
||||
resolveAlias: AliasResolver,
|
||||
) {
|
||||
const [typeAnnotation] = unwrapNullable<NativeModuleTypeAnnotation>(
|
||||
const [typeAnnotation, nullable] = unwrapNullable<NativeModuleTypeAnnotation>(
|
||||
nullableTypeAnnotation,
|
||||
);
|
||||
|
||||
let realTypeAnnotation = typeAnnotation;
|
||||
if (realTypeAnnotation.type === 'TypeAliasTypeAnnotation') {
|
||||
realTypeAnnotation = resolveAlias(realTypeAnnotation.name);
|
||||
}
|
||||
|
||||
function wrap(type) {
|
||||
return nullable ? `std::optional<${type}>` : type;
|
||||
}
|
||||
|
||||
switch (realTypeAnnotation.type) {
|
||||
case 'ReservedTypeAnnotation':
|
||||
switch (realTypeAnnotation.name) {
|
||||
case 'RootTag':
|
||||
return 'double';
|
||||
return wrap('double');
|
||||
default:
|
||||
(realTypeAnnotation.name: empty);
|
||||
throw new Error(createErrorMessage(realTypeAnnotation.name));
|
||||
@@ -130,27 +135,27 @@ function translatePrimitiveJSTypeToCpp(
|
||||
case 'VoidTypeAnnotation':
|
||||
return 'void';
|
||||
case 'StringTypeAnnotation':
|
||||
return 'jsi::String';
|
||||
return wrap('jsi::String');
|
||||
case 'NumberTypeAnnotation':
|
||||
return 'double';
|
||||
return wrap('double');
|
||||
case 'DoubleTypeAnnotation':
|
||||
return 'double';
|
||||
return wrap('double');
|
||||
case 'FloatTypeAnnotation':
|
||||
return 'double';
|
||||
return wrap('double');
|
||||
case 'Int32TypeAnnotation':
|
||||
return 'int';
|
||||
return wrap('int');
|
||||
case 'BooleanTypeAnnotation':
|
||||
return 'bool';
|
||||
return wrap('bool');
|
||||
case 'GenericObjectTypeAnnotation':
|
||||
return 'jsi::Object';
|
||||
return wrap('jsi::Object');
|
||||
case 'ObjectTypeAnnotation':
|
||||
return 'jsi::Object';
|
||||
return wrap('jsi::Object');
|
||||
case 'ArrayTypeAnnotation':
|
||||
return 'jsi::Array';
|
||||
return wrap('jsi::Array');
|
||||
case 'FunctionTypeAnnotation':
|
||||
return 'jsi::Function';
|
||||
return wrap('jsi::Function');
|
||||
case 'PromiseTypeAnnotation':
|
||||
return 'jsi::Value';
|
||||
return wrap('jsi::Value');
|
||||
default:
|
||||
(realTypeAnnotation.type: empty);
|
||||
throw new Error(createErrorMessage(realTypeAnnotation.type));
|
||||
|
||||
Reference in New Issue
Block a user