diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 90043816eeb5..53a94b7028a9 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -42,6 +42,10 @@ export type Int32TypeAnnotation = Readonly<{ type: 'Int32TypeAnnotation', }>; +export type BigIntTypeAnnotation = Readonly<{ + type: 'BigIntTypeAnnotation', +}>; + export type NumberLiteralTypeAnnotation = Readonly<{ type: 'NumberLiteralTypeAnnotation', value: number, @@ -418,6 +422,7 @@ export type NativeModuleBaseTypeAnnotation = | NumberLiteralTypeAnnotation | BooleanLiteralTypeAnnotation | Int32TypeAnnotation + | BigIntTypeAnnotation | DoubleTypeAnnotation | FloatTypeAnnotation | BooleanTypeAnnotation diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js index f6266693baa2..c7151ef0104f 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js @@ -119,6 +119,8 @@ function serializeArg( return wrap(val => `${val}.asNumber()`); case 'Int32TypeAnnotation': return wrap(val => `${val}.asNumber()`); + case 'BigIntTypeAnnotation': + return wrap(val => `jsi::Value(rt, ${val})`); case 'NumberLiteralTypeAnnotation': return wrap(val => `${val}.asNumber()`); case 'ArrayTypeAnnotation': @@ -267,6 +269,8 @@ function translatePrimitiveJSTypeToCpp( return wrapOptional('double', isRequired); case 'Int32TypeAnnotation': return wrapOptional('int', isRequired); + case 'BigIntTypeAnnotation': + return wrapOptional('BigInt', isRequired); case 'BooleanTypeAnnotation': return wrapOptional('bool', isRequired); case 'BooleanLiteralTypeAnnotation': @@ -601,6 +605,12 @@ function translateFunctionToCpp( enumMap, ); + // BigInt methods return BigInt from C++, but the callFromJs template + // parameter must be jsi::BigInt so the bridging layer converts via + // Bridging::toJs -> jsi::BigInt -> jsi::Value. + const callFromJsReturnType = + returnType === 'BigInt' ? 'jsi::BigInt' : returnType; + let methodCallArgs = [...args].join(',\n '); if (methodCallArgs.length > 0) { methodCallArgs = `,\n ${methodCallArgs}`; @@ -610,7 +620,7 @@ function translateFunctionToCpp( static_assert( bridging::getParameterCount(&T::${prop.name}) == ${paramTypes.length}, "Expected ${prop.name}(...) to have ${paramTypes.length} parameters"); - ${!isVoid ? (!isNullable ? 'return ' : 'auto result = ') : ''}bridging::callFromJs<${returnType}>(rt, &T::${prop.name}, static_cast<${hasteModuleName}CxxSpec*>(&turboModule)->jsInvoker_, static_cast(&turboModule)${methodCallArgs});${!isVoid ? (!isNullable ? '' : 'return result ? jsi::Value(std::move(*result)) : jsi::Value::null();') : 'return jsi::Value::undefined();'}\n }`; + ${!isVoid ? (!isNullable ? 'return ' : 'auto result = ') : ''}bridging::callFromJs<${callFromJsReturnType}>(rt, &T::${prop.name}, static_cast<${hasteModuleName}CxxSpec*>(&turboModule)->jsInvoker_, static_cast(&turboModule)${methodCallArgs});${!isVoid ? (!isNullable ? '' : 'return result ? jsi::Value(std::move(*result)) : jsi::Value::null();') : 'return jsi::Value::undefined();'}\n }`; } type EventEmitterCpp = { diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js index 98ed68318f83..0ebbe1bf5d12 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js @@ -155,6 +155,9 @@ function translateEventEmitterTypeToJavaType( case 'DoubleTypeAnnotation': case 'Int32TypeAnnotation': return 'double'; + case 'BigIntTypeAnnotation': + imports.add('java.math.BigInteger'); + return 'BigInteger'; case 'BooleanTypeAnnotation': case 'BooleanLiteralTypeAnnotation': return 'boolean'; @@ -267,6 +270,12 @@ function translateFunctionParamToJavaType( case 'FunctionTypeAnnotation': imports.add('com.facebook.react.bridge.Callback'); return wrapOptional('Callback', isRequired); + case 'BigIntTypeAnnotation': + throw new Error( + createErrorMessage( + `${realTypeAnnotation.type} is not supported in Java TurboModules yet`, + ), + ); default: realTypeAnnotation.type as 'MixedTypeAnnotation'; throw new Error(createErrorMessage(realTypeAnnotation.type)); @@ -361,6 +370,12 @@ function translateFunctionReturnTypeToJavaType( case 'ArrayTypeAnnotation': imports.add('com.facebook.react.bridge.WritableArray'); return wrapOptional('WritableArray', isRequired); + case 'BigIntTypeAnnotation': + throw new Error( + createErrorMessage( + `${realTypeAnnotation.type} is not supported in Java TurboModules yet`, + ), + ); default: realTypeAnnotation.type as 'MixedTypeAnnotation'; throw new Error(createErrorMessage(realTypeAnnotation.type)); @@ -443,6 +458,8 @@ function getFalsyReturnStatementFromReturnType( return 'return null;'; case 'ArrayTypeAnnotation': return 'return null;'; + case 'BigIntTypeAnnotation': + throw new Error(createErrorMessage(realTypeAnnotation.type)); default: realTypeAnnotation.type as 'MixedTypeAnnotation'; throw new Error(createErrorMessage(realTypeAnnotation.type)); diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js index 55be945773f4..d0326fd6b330 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js @@ -33,6 +33,7 @@ type JSReturnType = | 'StringKind' | 'BooleanKind' | 'NumberKind' + | 'BigIntKind' | 'PromiseKind' | 'ObjectKind' | 'ArrayKind'; @@ -208,6 +209,8 @@ function translateReturnTypeToKind( return 'NumberKind'; case 'Int32TypeAnnotation': return 'NumberKind'; + case 'BigIntTypeAnnotation': + return 'BigIntKind'; case 'PromiseTypeAnnotation': return 'PromiseKind'; case 'GenericObjectTypeAnnotation': @@ -295,6 +298,10 @@ function translateParamTypeToJniType( return !isRequired ? 'Ljava/lang/Double;' : 'D'; case 'Int32TypeAnnotation': return !isRequired ? 'Ljava/lang/Double;' : 'D'; + case 'BigIntTypeAnnotation': + throw new Error( + `${realTypeAnnotation.type} is not supported in Java TurboModules yet`, + ); case 'GenericObjectTypeAnnotation': return 'Lcom/facebook/react/bridge/ReadableMap;'; case 'ObjectTypeAnnotation': @@ -379,6 +386,10 @@ function translateReturnTypeToJniType( return nullable ? 'Ljava/lang/Double;' : 'D'; case 'Int32TypeAnnotation': return nullable ? 'Ljava/lang/Double;' : 'D'; + case 'BigIntTypeAnnotation': + throw new Error( + `${realTypeAnnotation.type} is not supported in Java TurboModules yet`, + ); case 'PromiseTypeAnnotation': return 'Lcom/facebook/react/bridge/Promise;'; case 'GenericObjectTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js index 2cc39108680b..9988e3439712 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js @@ -11,6 +11,7 @@ 'use strict'; import type { + BigIntTypeAnnotation, BooleanLiteralTypeAnnotation, BooleanTypeAnnotation, DoubleTypeAnnotation, @@ -72,6 +73,7 @@ export type StructTypeAnnotation = | NumberLiteralTypeAnnotation | BooleanLiteralTypeAnnotation | Int32TypeAnnotation + | BigIntTypeAnnotation | DoubleTypeAnnotation | FloatTypeAnnotation | BooleanTypeAnnotation diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js index 065de9be18ea..e77137b0d291 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js @@ -115,6 +115,8 @@ function toObjCValue( return wrapPrimitive('double'); case 'Int32TypeAnnotation': return wrapPrimitive('double'); + case 'BigIntTypeAnnotation': + return value; case 'DoubleTypeAnnotation': return wrapPrimitive('double'); case 'BooleanTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js index 056eed66d3f0..f2bbd1411a7a 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js @@ -106,6 +106,8 @@ function toObjCValue( return RCTBridgingTo('Double'); case 'Int32TypeAnnotation': return RCTBridgingTo('Double'); + case 'BigIntTypeAnnotation': + return RCTBridgingTo('NSNumber'); case 'DoubleTypeAnnotation': return RCTBridgingTo('Double'); case 'BooleanTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js index c618b0f78c54..c029abbfed17 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js @@ -51,6 +51,7 @@ type ReturnJSType = | 'ObjectKind' | 'ArrayKind' | 'NumberKind' + | 'BigIntKind' | 'StringKind'; export type MethodSerializationOutput = Readonly<{ @@ -272,6 +273,8 @@ function getParamObjCType( return notStruct(isRequired ? 'double' : 'NSNumber *'); case 'Int32TypeAnnotation': return notStruct(isRequired ? 'NSInteger' : 'NSNumber *'); + case 'BigIntTypeAnnotation': + return notStruct(wrapOptional('NSNumber *', !nullable)); case 'BooleanTypeAnnotation': return notStruct(isRequired ? 'BOOL' : 'NSNumber *'); case 'BooleanLiteralTypeAnnotation': @@ -353,6 +356,8 @@ function getReturnObjCType( return wrapOptional('NSNumber *', isRequired); case 'Int32TypeAnnotation': return wrapOptional('NSNumber *', isRequired); + case 'BigIntTypeAnnotation': + return wrapOptional('NSNumber *', isRequired); case 'BooleanTypeAnnotation': return wrapOptional('NSNumber *', isRequired); case 'BooleanLiteralTypeAnnotation': @@ -427,6 +432,8 @@ function getReturnJSType( return 'NumberKind'; case 'Int32TypeAnnotation': return 'NumberKind'; + case 'BigIntTypeAnnotation': + return 'BigIntKind'; case 'BooleanTypeAnnotation': return 'BooleanKind'; case 'BooleanLiteralTypeAnnotation': diff --git a/packages/react-native-codegen/src/parsers/parsers-primitives.js b/packages/react-native-codegen/src/parsers/parsers-primitives.js index 3243a9a95cfd..c915ad5adcbf 100644 --- a/packages/react-native-codegen/src/parsers/parsers-primitives.js +++ b/packages/react-native-codegen/src/parsers/parsers-primitives.js @@ -11,6 +11,7 @@ 'use strict'; import type { + BigIntTypeAnnotation, BooleanLiteralTypeAnnotation, BooleanTypeAnnotation, DoubleTypeAnnotation, @@ -87,6 +88,12 @@ function emitInt32Prop( }; } +function emitBigInt(nullable: boolean): Nullable { + return wrapNullable(nullable, { + type: 'BigIntTypeAnnotation', + }); +} + function emitNumber( nullable: boolean, ): Nullable { @@ -652,6 +659,8 @@ function emitCommonTypes( const typeMap = { Stringish: emitStringish, Int32: emitInt32, + BigInt: emitBigInt, + BigIntTypeAnnotation: emitBigInt, Double: emitDouble, Float: emitFloat, UnsafeObject: emitGenericObject, diff --git a/packages/react-native-codegen/src/parsers/typescript/parser.js b/packages/react-native-codegen/src/parsers/typescript/parser.js index 86c9bdfade58..5d01616a4bd8 100644 --- a/packages/react-native-codegen/src/parsers/typescript/parser.js +++ b/packages/react-native-codegen/src/parsers/typescript/parser.js @@ -393,6 +393,8 @@ class TypeScriptParser implements Parser { return 'ArrayTypeAnnotation'; case 'TSBooleanKeyword': return 'BooleanTypeAnnotation'; + case 'TSBigIntKeyword': + return 'BigIntTypeAnnotation'; case 'TSNumberKeyword': return 'NumberTypeAnnotation'; case 'TSVoidKeyword': diff --git a/packages/react-native-compatibility-check/src/ErrorFormatting.js b/packages/react-native-compatibility-check/src/ErrorFormatting.js index 8f7fb95770d3..a1b9cd39ce3b 100644 --- a/packages/react-native-compatibility-check/src/ErrorFormatting.js +++ b/packages/react-native-compatibility-check/src/ErrorFormatting.js @@ -170,6 +170,8 @@ function formatTypeAnnotation(annotation: CompleteTypeAnnotation): string { return 'float'; case 'Int32TypeAnnotation': return 'int'; + case 'BigIntTypeAnnotation': + return 'bigint'; case 'NumberLiteralTypeAnnotation': return annotation.value.toString(); case 'BooleanLiteralTypeAnnotation': diff --git a/packages/react-native-compatibility-check/src/SortTypeAnnotations.js b/packages/react-native-compatibility-check/src/SortTypeAnnotations.js index 81b2e425f861..7042b6b44b42 100644 --- a/packages/react-native-compatibility-check/src/SortTypeAnnotations.js +++ b/packages/react-native-compatibility-check/src/SortTypeAnnotations.js @@ -110,6 +110,7 @@ export function compareTypeAnnotationForSorting( ); case 'NumberTypeAnnotation': case 'Int32TypeAnnotation': + case 'BigIntTypeAnnotation': case 'FloatTypeAnnotation': case 'DoubleTypeAnnotation': return 0; @@ -281,6 +282,8 @@ function typeAnnotationArbitraryOrder(annotation: CompleteTypeAnnotation) { return 28; case 'UnionTypeAnnotation': return 30; + case 'BigIntTypeAnnotation': + return 31; default: annotation.type as empty; return -1; diff --git a/packages/react-native-compatibility-check/src/TypeDiffing.js b/packages/react-native-compatibility-check/src/TypeDiffing.js index bdc081aeeef7..564623704265 100644 --- a/packages/react-native-compatibility-check/src/TypeDiffing.js +++ b/packages/react-native-compatibility-check/src/TypeDiffing.js @@ -179,6 +179,7 @@ export function compareTypeAnnotation( case 'DoubleTypeAnnotation': case 'FloatTypeAnnotation': case 'Int32TypeAnnotation': + case 'BigIntTypeAnnotation': case 'BooleanTypeAnnotation': case 'NumberTypeAnnotation': case 'StringTypeAnnotation': diff --git a/packages/react-native/ReactCommon/react/bridging/BigInt.h b/packages/react-native/ReactCommon/react/bridging/BigInt.h new file mode 100644 index 000000000000..8c6156d1a39a --- /dev/null +++ b/packages/react-native/ReactCommon/react/bridging/BigInt.h @@ -0,0 +1,81 @@ +/* + * 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 +#include + +namespace facebook::react { + +class BigInt { + public: + BigInt(jsi::Runtime &rt, const jsi::BigInt &bigint) + { + if (bigint.isInt64(rt)) { + value_ = bigint.asInt64(rt); + } else if (bigint.isUint64(rt)) { + value_ = bigint.asUint64(rt); + } else { + throw jsi::JSError(rt, "BigInt value cannot be losslessly represented as int64_t or uint64_t"); + } + } + + /* implicit */ BigInt(int64_t value) : value_(value) {} + /* implicit */ BigInt(uint64_t value) : value_(value) {} + + bool isInt64() const + { + return std::holds_alternative(value_); + } + + bool isUint64() const + { + return std::holds_alternative(value_); + } + + int64_t asInt64() const + { + return std::get(value_); + } + + uint64_t asUint64() const + { + return std::get(value_); + } + + jsi::BigInt toJSBigInt(jsi::Runtime &rt) const + { + if (isInt64()) { + return jsi::BigInt::fromInt64(rt, asInt64()); + } else { + return jsi::BigInt::fromUint64(rt, asUint64()); + } + } + + bool operator==(const BigInt &other) const = default; + + private: + std::variant value_; +}; + +template <> +struct Bridging { + static BigInt fromJs(jsi::Runtime &rt, const jsi::Value &value) + { + return {rt, value.getBigInt(rt)}; + } + + static jsi::BigInt toJs(jsi::Runtime &rt, const BigInt &value) + { + return value.toJSBigInt(rt); + } +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/bridging/Bridging.h b/packages/react-native/ReactCommon/react/bridging/Bridging.h index 558d91335f6c..51c9b8b11699 100644 --- a/packages/react-native/ReactCommon/react/bridging/Bridging.h +++ b/packages/react-native/ReactCommon/react/bridging/Bridging.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp b/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp index 8faa39791316..fc279a6bfc7c 100644 --- a/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp +++ b/packages/react-native/ReactCommon/react/bridging/tests/BridgingTest.cpp @@ -7,6 +7,10 @@ #include "BridgingTest.h" +#include +#include +#include + namespace facebook::react { using namespace std::literals; @@ -798,4 +802,87 @@ TEST_F(BridgingTest, highResTimeStampTest) { 1.000001, bridging::toJs(rt, HighResDuration::fromNanoseconds(1e6 + 1))); } +TEST_F(BridgingTest, bigintTest) { + // Test BigInt construction from int64_t + BigInt fromSigned(static_cast(42)); + EXPECT_TRUE(fromSigned.isInt64()); + EXPECT_FALSE(fromSigned.isUint64()); + EXPECT_EQ(42, fromSigned.asInt64()); + + // Test BigInt construction from uint64_t + BigInt fromUnsigned(static_cast(42)); + EXPECT_FALSE(fromUnsigned.isInt64()); + EXPECT_TRUE(fromUnsigned.isUint64()); + EXPECT_EQ(42ULL, fromUnsigned.asUint64()); + + // Test BigInt construction from jsi::BigInt with signed value + auto jsiBigint = jsi::BigInt::fromInt64(rt, -123456789012345LL); + BigInt fromJsi(rt, jsiBigint); + EXPECT_TRUE(fromJsi.isInt64()); + EXPECT_EQ(-123456789012345LL, fromJsi.asInt64()); + + // Test BigInt construction from jsi::BigInt with large unsigned value + // (doesn't fit in int64_t, so should be stored as uint64_t) + constexpr uint64_t uint64Max = std::numeric_limits::max(); + auto jsiUnsigned = jsi::BigInt::fromUint64(rt, uint64Max); + BigInt fromJsiUnsigned(rt, jsiUnsigned); + EXPECT_TRUE(fromJsiUnsigned.isUint64()); + EXPECT_EQ(uint64Max, fromJsiUnsigned.asUint64()); + + // Test BigInt construction from jsi::BigInt with small positive value + // (fits in both int64_t and uint64_t — should prefer int64_t) + auto jsiSmall = jsi::BigInt::fromInt64(rt, 5); + BigInt fromJsiSmall(rt, jsiSmall); + EXPECT_TRUE(fromJsiSmall.isInt64()); + EXPECT_EQ(5, fromJsiSmall.asInt64()); + + // Test toJSBigInt roundtrip for signed value + BigInt signedVal(static_cast(-42)); + auto jsResult = signedVal.toJSBigInt(rt); + EXPECT_EQ(-42, jsResult.asInt64(rt)); + + // Test toJSBigInt roundtrip for unsigned value + BigInt unsignedVal(uint64Max); + auto jsUnsignedResult = unsignedVal.toJSBigInt(rt); + EXPECT_EQ(uint64Max, jsUnsignedResult.asUint64(rt)); + + // Test Bridging::fromJs + constexpr int64_t int64Max = std::numeric_limits::max(); + auto jsBigint = jsi::BigInt::fromInt64(rt, int64Max); + auto bridged = + bridging::fromJs(rt, jsi::Value(rt, jsBigint), invoker); + EXPECT_TRUE(bridged.isInt64()); + EXPECT_EQ(int64Max, bridged.asInt64()); + + // Test Bridging::toJs + BigInt toConvert(static_cast(123456789012345LL)); + auto jsConverted = bridging::toJs(rt, toConvert); + EXPECT_EQ(123456789012345LL, jsConverted.asInt64(rt)); + + // Test roundtrip at extreme values via bridging + constexpr int64_t int64Min = std::numeric_limits::min(); + + auto roundtripMin = bridging::fromJs( + rt, jsi::Value(rt, bridging::toJs(rt, BigInt(int64Min))), invoker); + EXPECT_TRUE(roundtripMin.isInt64()); + EXPECT_EQ(int64Min, roundtripMin.asInt64()); + + auto roundtripMax = bridging::fromJs( + rt, jsi::Value(rt, bridging::toJs(rt, BigInt(int64Max))), invoker); + EXPECT_TRUE(roundtripMax.isInt64()); + EXPECT_EQ(int64Max, roundtripMax.asInt64()); + + auto roundtripUmax = bridging::fromJs( + rt, jsi::Value(rt, bridging::toJs(rt, BigInt(uint64Max))), invoker); + EXPECT_TRUE(roundtripUmax.isUint64()); + EXPECT_EQ(uint64Max, roundtripUmax.asUint64()); + + // Test equality + EXPECT_EQ(BigInt(static_cast(42)), BigInt(static_cast(42))); + EXPECT_EQ(BigInt(uint64Max), BigInt(uint64Max)); + // Same numeric value but different variant type are not equal + EXPECT_NE( + BigInt(static_cast(42)), BigInt(static_cast(42))); +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModule.cpp b/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModule.cpp index 193773b6441e..d0e43cf88955 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModule.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModule.cpp @@ -21,6 +21,8 @@ TurboModuleMethodValueKind getTurboModuleMethodValueKind( return NumberKind; } else if (value->isString()) { return StringKind; + } else if (value->isBigInt()) { + return BigIntKind; } else if (value->isObject()) { auto object = value->asObject(rt); if (object.isArray(rt)) { diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModule.h b/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModule.h index f1d51678bf54..b6ac2f2e5984 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModule.h +++ b/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModule.h @@ -26,6 +26,7 @@ enum TurboModuleMethodValueKind { VoidKind, BooleanKind, NumberKind, + BigIntKind, StringKind, ObjectKind, ArrayKind, diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm index a1111f9c8565..9d9ba7e497c0 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm @@ -526,6 +526,10 @@ TraceSection s( throw jsi::JSError(runtime, "convertReturnIdToJSIValue: FunctionKind is not supported yet."); case PromiseKind: throw jsi::JSError(runtime, "convertReturnIdToJSIValue: PromiseKind wasn't handled properly."); + case BigIntKind: { + returnValue = jsi::BigInt::fromInt64(runtime, [(NSNumber *)result longLongValue]); + break; + } } return returnValue; @@ -813,7 +817,8 @@ TraceSection s( case StringKind: case ObjectKind: case ArrayKind: - case FunctionKind: { + case FunctionKind: + case BigIntKind: { id result = performMethodInvocation(runtime, true, methodName, inv, retainedObjectsForInvocation); TurboModulePerfLogger::syncMethodCallReturnConversionStart(moduleName, methodName); returnValue = convertReturnIdToJSIValue(runtime, methodName, returnType, result); diff --git a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.cpp b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.cpp index 492c29a33b66..cc3958e28510 100644 --- a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.cpp +++ b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.cpp @@ -7,6 +7,7 @@ #include "NativeCxxModuleExample.h" #include +#include #include #include #include @@ -265,4 +266,8 @@ AsyncPromise<> NativeCxxModuleExample::promiseAssert(jsi::Runtime& rt) { return promise; }; +BigInt NativeCxxModuleExample::getBigInt(jsi::Runtime& /*rt*/, BigInt arg) { + return arg; +} + } // namespace facebook::react diff --git a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h index 9c2ce01677b1..b8ddd52ab3b8 100644 --- a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h +++ b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.h @@ -182,6 +182,8 @@ class NativeCxxModuleExample : public NativeCxxModuleExampleCxxSpec promiseAssert(jsi::Runtime &rt); + BigInt getBigInt(jsi::Runtime &rt, BigInt arg); + private: std::optional> valueCallback_; }; diff --git a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.js b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.js index 589360363a32..be16fd21277b 100644 --- a/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.js +++ b/packages/rn-tester/NativeCxxModuleExample/NativeCxxModuleExample.js @@ -114,6 +114,7 @@ export interface Spec extends TurboModule { +voidFuncAssert: () => void; +getObjectAssert: (arg: ObjectStruct) => ObjectStruct; +promiseAssert: () => Promise; + +getBigInt: (arg: bigint) => bigint; } export default TurboModuleRegistry.get( diff --git a/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js b/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js index dcee38ad6560..8c8e22780e2d 100644 --- a/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js +++ b/packages/rn-tester/js/examples/TurboModule/NativeCxxModuleExampleExample.js @@ -50,6 +50,7 @@ type Examples = | 'getStrEnum' | 'getMap' | 'getNumber' + | 'getBigInt' | 'getObject' | 'getSet' | 'getString' @@ -122,7 +123,10 @@ class NativeCxxModuleExampleExample extends React.Component<{}, State> { }), getNumEnum: () => NativeCxxModuleExample?.getNumEnum(EnumInt.IB), getStrEnum: () => NativeCxxModuleExample?.getStrEnum(EnumNone.NB), + getMap: () => NativeCxxModuleExample?.getMap({one: 1, two: 2, three: null}), getNumber: () => NativeCxxModuleExample?.getNumber(99.95), + getBigInt: () => + NativeCxxModuleExample?.getBigInt(BigInt('9223372036854775807')), getObject: () => NativeCxxModuleExample?.getObject({a: 1, b: 'foo', c: null}), getSet: () => NativeCxxModuleExample?.getSet([1, 1.1, 1.1, 1.1, 2]), @@ -259,7 +263,9 @@ class NativeCxxModuleExampleExample extends React.Component<{}, State> { return ( - {JSON.stringify(result.value)} + {typeof result.value === 'bigint' + ? result.value.toString() + : JSON.stringify(result.value)} {result.type}