Skip to content

Commit 4e048fa

Browse files
christophpurrermeta-codesync[bot]
authored andcommitted
Add BigInt Support to Objective-C Turbo Module (#56020)
Summary: Pull Request resolved: #56020 This diff adds BigInt method support to the Objective-C sample Turbo Module, demonstrating how to use 64-bit integers with BigInt bridging on iOS. Changes: - Added getBigInt method declaration in RCTNativeSampleTurboModuleSpec.h using C++ int64_t type - Added host function binding in RCTNativeSampleTurboModuleSpec.mm using BigIntKind - Implemented getBigInt in RCTSampleTurboModule.mm using RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD - Fixed BigInt rendering in NativeCxxModuleExampleExample.js and SampleTurboModuleExample.js — JSON.stringify() cannot serialize BigInt, so bigint values are now rendered via .toString() The ObjC bridge maps getBigInt to an NSNumber* return with BigIntKind, which instructs the TurboModule infrastructure to convert via jsi::BigInt::fromInt64(). ## Conversion Table | NSNumber Method | Underlying Type | Min | Max | | --- | --- | --- | --- | | numberWithChar: | char | -128 | 127 | | numberWithShort: | short | -32,768 | 32,767 | | numberWithInt: | int | -2,147,483,648 | 2,147,483,647 | | numberWithLongLong: | long long | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 | | numberWithUnsignedLongLong: | unsigned long long | 0 | 18,446,744,073,709,551,615 | Changelog: [iOS][Added] - Add BigInt Support to Objective-C Turbo Module Differential Revision: D95232266
1 parent e89b115 commit 4e048fa

4 files changed

Lines changed: 72 additions & 3 deletions

File tree

packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#import <objc/message.h>
2626
#import <objc/runtime.h>
2727
#import <atomic>
28+
#import <cstring>
2829
#import <iostream>
2930
#import <mutex>
3031

@@ -188,6 +189,16 @@ id convertJSIValueToObjCObject(
188189
if (value.isString()) {
189190
return convertJSIStringToNSString(runtime, value.getString(runtime));
190191
}
192+
if (value.isBigInt()) {
193+
auto bigint = value.getBigInt(runtime);
194+
if (bigint.isInt64(runtime)) {
195+
return [NSNumber numberWithLongLong:bigint.getInt64(runtime)];
196+
}
197+
if (bigint.isUint64(runtime)) {
198+
return [NSNumber numberWithUnsignedLongLong:bigint.getUint64(runtime)];
199+
}
200+
throw jsi::JSError(runtime, "BigInt value is too large for int64_t or uint64_t");
201+
}
191202
if (value.isObject()) {
192203
jsi::Object o = value.getObject(runtime);
193204
if (o.isArray(runtime)) {
@@ -526,7 +537,14 @@ TraceSection s(
526537
case PromiseKind:
527538
throw jsi::JSError(runtime, "convertReturnIdToJSIValue: PromiseKind wasn't handled properly.");
528539
case BigIntKind: {
529-
returnValue = jsi::BigInt::fromInt64(runtime, [(NSNumber *)result longLongValue]);
540+
auto num = (NSNumber *)result;
541+
const char *type = [num objCType];
542+
if (type != nullptr &&
543+
(strcmp(type, @encode(unsigned long long)) == 0 || strcmp(type, @encode(unsigned long)) == 0)) {
544+
returnValue = jsi::BigInt::fromUint64(runtime, [num unsignedLongLongValue]);
545+
} else {
546+
returnValue = jsi::BigInt::fromInt64(runtime, [num longLongValue]);
547+
}
530548
break;
531549
}
532550
}
@@ -630,9 +648,40 @@ TraceSection s(
630648
[retainedObjectsForInvocation addObject:objCArg];
631649
} else if (objCArgType == @encode(NSInteger)) {
632650
NSInteger integer = v;
633-
[inv setArgument:&integer atIndex:i + 2];
651+
[inv setArgument:&integer atIndex:static_cast<NSInteger>(i + 2)];
634652
} else {
635-
[inv setArgument:(void *)&v atIndex:i + 2];
653+
[inv setArgument:(void *)&v atIndex:static_cast<NSInteger>(i + 2)];
654+
}
655+
656+
return;
657+
}
658+
659+
if (arg.isBigInt()) {
660+
auto bigint = arg.getBigInt(runtime);
661+
662+
/**
663+
* JS type checking ensures the Objective C argument here is either a long long or NSNumber*.
664+
*/
665+
if (bigint.isInt64(runtime)) {
666+
int64_t v = bigint.getInt64(runtime);
667+
if (objCArgType == @encode(id)) {
668+
id objCArg = [NSNumber numberWithLongLong:v];
669+
[inv setArgument:(void *)&objCArg atIndex:static_cast<NSInteger>(i + 2)];
670+
[retainedObjectsForInvocation addObject:objCArg];
671+
} else {
672+
[inv setArgument:(void *)&v atIndex:static_cast<NSInteger>(i + 2)];
673+
}
674+
} else if (bigint.isUint64(runtime)) {
675+
uint64_t v = bigint.getUint64(runtime);
676+
if (objCArgType == @encode(id)) {
677+
id objCArg = [NSNumber numberWithUnsignedLongLong:v];
678+
[inv setArgument:(void *)&objCArg atIndex:static_cast<NSInteger>(i + 2)];
679+
[retainedObjectsForInvocation addObject:objCArg];
680+
} else {
681+
[inv setArgument:(void *)&v atIndex:static_cast<NSInteger>(i + 2)];
682+
}
683+
} else {
684+
throw jsi::JSError(runtime, "BigInt value is too large for int64_t or uint64_t");
636685
}
637686

638687
return;

packages/react-native/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTNativeSampleTurboModuleSpec.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
// NOTE: This entire file should be codegen'ed.
99

10+
#import <cstdint>
1011
#import <vector>
1112

1213
#ifndef __cplusplus
@@ -104,6 +105,7 @@ inline JS::NativeSampleTurboModule::Constants::Builder::Builder(Constants i)
104105
- (NSDictionary *)getObjectAssert:(NSDictionary *)arg;
105106
- (void)promiseAssert:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
106107
- (void)getImageUrl:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
108+
- (NSNumber *)getBigInt:(int64_t)arg;
107109
- (facebook::react::ModuleConstants<JS::NativeSampleTurboModule::Constants>)constantsToExport;
108110
- (facebook::react::ModuleConstants<JS::NativeSampleTurboModule::Constants>)getConstants;
109111

packages/react-native/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTNativeSampleTurboModuleSpec.mm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,16 @@ - (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallb
214214
.invokeObjCMethod(rt, PromiseKind, "promiseAssert", @selector(promiseAssert:reject:), args, count);
215215
}
216216

217+
static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getBigInt(
218+
facebook::jsi::Runtime &rt,
219+
TurboModule &turboModule,
220+
const facebook::jsi::Value *args,
221+
size_t count)
222+
{
223+
return static_cast<ObjCTurboModule &>(turboModule)
224+
.invokeObjCMethod(rt, BigIntKind, "getBigInt", @selector(getBigInt:), args, count);
225+
}
226+
217227
static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getImageUrl(
218228
facebook::jsi::Runtime &rt,
219229
TurboModule &turboModule,
@@ -275,6 +285,9 @@ - (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallb
275285

276286
methodMap_["promiseAssert"] = MethodMetadata{0, __hostFunction_NativeSampleTurboModuleSpecJSI_promiseAssert};
277287

288+
methodMap_["getBigInt"] =
289+
MethodMetadata{.argCount = 1, .invoker = __hostFunction_NativeSampleTurboModuleSpecJSI_getBigInt};
290+
278291
methodMap_["getImageUrl"] = MethodMetadata{0, __hostFunction_NativeSampleTurboModuleSpecJSI_getImageUrl};
279292

280293
methodMap_["getConstants"] = MethodMetadata{0, __hostFunction_NativeSampleTurboModuleSpecJSI_getConstants};

packages/react-native/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTSampleTurboModule.mm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,11 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
210210
RCTAssert(false, @"Intentional assert from ObjC promiseAssert");
211211
}
212212

213+
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSNumber *, getBigInt : (int64_t)arg)
214+
{
215+
return @(arg);
216+
}
217+
213218
@end
214219

215220
Class _Nonnull RCTSampleTurboModuleCls(void)

0 commit comments

Comments
 (0)