diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js index efb710aaae0a..3f0b4f8f24dc 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js @@ -25,11 +25,7 @@ import type {AliasResolver} from './Utils'; const {unwrapNullable} = require('../../parsers/parsers-commons'); const {wrapOptional} = require('../TypeUtils/Java'); const {parseValidUnionType, toPascalCase} = require('../Utils'); -const { - createAliasResolver, - getModules, - throwIfUnsupportedPromiseArrayBuffer, -} = require('./Utils'); +const {createAliasResolver, getModules} = require('./Utils'); type FilesOutput = Map; @@ -590,11 +586,6 @@ module.exports = { method.typeAnnotation, ); - throwIfUnsupportedPromiseArrayBuffer( - method.name, - methodTypeAnnotation.returnTypeAnnotation, - ); - // Handle return type const translatedReturnType = translateFunctionReturnTypeToJavaType( methodTypeAnnotation.returnTypeAnnotation, diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js index 56bc6f941800..8f039d960867 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js @@ -24,11 +24,7 @@ import type {AliasResolver} from './Utils'; const {unwrapNullable} = require('../../parsers/parsers-commons'); const {parseValidUnionType} = require('../Utils'); -const { - createAliasResolver, - getModules, - throwIfUnsupportedPromiseArrayBuffer, -} = require('./Utils'); +const {createAliasResolver, getModules} = require('./Utils'); type FilesOutput = Map; @@ -47,15 +43,20 @@ const HostFunctionTemplate = ({ propertyName, jniSignature, jsReturnType, + promiseResolveSupportsArrayBuffer, }: Readonly<{ hasteModuleName: string, propertyName: string, jniSignature: string, jsReturnType: JSReturnType, + promiseResolveSupportsArrayBuffer: boolean, }>) => { + const promiseResolveSupportsArrayBufferArg = `, ${ + promiseResolveSupportsArrayBuffer ? 'true' : 'false' + }`; return `static facebook::jsi::Value __hostFunction_${hasteModuleName}SpecJSI_${propertyName}(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, ${jsReturnType}, "${propertyName}", "${jniSignature}", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, ${jsReturnType}, "${propertyName}", "${jniSignature}", args, count, cachedMethodId${promiseResolveSupportsArrayBufferArg}); }`; }; @@ -406,6 +407,23 @@ function translateReturnTypeToJniType( } } +function doesPromiseResolveSupportArrayBuffer( + nullableReturnTypeAnnotation: Nullable, +): boolean { + const [returnTypeAnnotation] = + unwrapNullable( + nullableReturnTypeAnnotation, + ); + if (returnTypeAnnotation.type !== 'PromiseTypeAnnotation') { + return false; + } + + let elementType = returnTypeAnnotation.elementType; + [elementType] = unwrapNullable(elementType); + + return elementType.type === 'ArrayBufferTypeAnnotation'; +} + function translateMethodTypeToJniSignature( property: NativeModulePropertyShape, resolveAlias: AliasResolver, @@ -453,8 +471,6 @@ function translateMethodForImplementation( unwrapNullable(property.typeAnnotation); const {returnTypeAnnotation} = propertyTypeAnnotation; - throwIfUnsupportedPromiseArrayBuffer(property.name, returnTypeAnnotation); - if ( property.name === 'getConstants' && returnTypeAnnotation.type === 'ObjectTypeAnnotation' && @@ -468,6 +484,8 @@ function translateMethodForImplementation( propertyName: property.name, jniSignature: translateMethodTypeToJniSignature(property, resolveAlias), jsReturnType: translateReturnTypeToKind(returnTypeAnnotation, resolveAlias), + promiseResolveSupportsArrayBuffer: + doesPromiseResolveSupportArrayBuffer(returnTypeAnnotation), }); } 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 6811646078e2..928ddf0e4502 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js @@ -26,7 +26,6 @@ const { } = require('../../../parsers/parsers-commons'); const {wrapOptional} = require('../../TypeUtils/Objective-C'); const {capitalize, parseValidUnionType} = require('../../Utils'); -const {throwIfUnsupportedPromiseArrayBuffer} = require('../Utils'); const {getNamespacedStructName} = require('./Utils'); const invariant = require('invariant'); @@ -104,11 +103,6 @@ function serializeMethod( } }); - throwIfUnsupportedPromiseArrayBuffer( - methodName, - propertyTypeAnnotation.returnTypeAnnotation, - ); - // Unwrap returnTypeAnnotation, so we check if the return type is Promise // TODO(T76719514): Disallow nullable PromiseTypeAnnotations const [returnTypeAnnotation] = unwrapNullable( diff --git a/packages/react-native-codegen/src/generators/modules/Utils.js b/packages/react-native-codegen/src/generators/modules/Utils.js index 8cd8d37ff096..ce6b63398417 100644 --- a/packages/react-native-codegen/src/generators/modules/Utils.js +++ b/packages/react-native-codegen/src/generators/modules/Utils.js @@ -13,7 +13,6 @@ import type { NativeModuleAliasMap, NativeModuleObjectTypeAnnotation, - NativeModuleReturnTypeAnnotation, NativeModuleSchema, NativeModuleTypeAnnotation, Nullable, @@ -78,50 +77,9 @@ function isArrayRecursiveMember( ); } -// Platform-native (Java/Kotlin and ObjC) TurboModules copy ArrayBuffer -// arguments and return ArrayBuffers zero-copy from synchronous methods, but -// `Promise` is not part of their contract. -// -// On Android it cannot work: the resolve path serializes through -// folly::dynamic, which cannot carry raw bytes. On iOS the resolve path is a -// direct ObjC->jsi conversion that would in fact produce an ArrayBuffer for an -// NSMutableData, so the limitation there is not technical — the guard is -// applied to ObjC as well to keep one cross-platform contract, so a spec that -// compiles for iOS cannot fail to build for Android. -// -// Reject `Promise` at codegen time for both native platforms so -// the unsupported case surfaces as a build error rather than a runtime failure -// or a silent iOS/Android divergence. -function throwIfUnsupportedPromiseArrayBuffer( - methodName: string, - nullableReturnTypeAnnotation: Nullable, -): void { - const [returnTypeAnnotation] = - unwrapNullable( - nullableReturnTypeAnnotation, - ); - if (returnTypeAnnotation.type !== 'PromiseTypeAnnotation') { - return; - } - let elementType = returnTypeAnnotation.elementType; - if (elementType.type === 'NullableTypeAnnotation') { - elementType = elementType.typeAnnotation; - } - if (elementType.type === 'ArrayBufferTypeAnnotation') { - throw new Error( - `Unsupported return type for method "${methodName}": Promise is not ` + - 'supported for Android (Java/Kotlin) or iOS (ObjC) TurboModules. Use a C++ ' + - '(Cxx) TurboModule, return the ArrayBuffer from a synchronous method, or resolve ' + - 'the Promise with a different type. ArrayBuffer is still supported as a method ' + - 'argument and as a synchronous return value on all platforms.', - ); - } -} - module.exports = { createAliasResolver, getModules, isDirectRecursiveMember, isArrayRecursiveMember, - throwIfUnsupportedPromiseArrayBuffer, }; diff --git a/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js index 83cc98bef054..9ad6453a0d69 100644 --- a/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js @@ -2661,25 +2661,6 @@ const ARRAY_BUFFER_NATIVE_MODULE: SchemaType = { ], }, }, - ], - }, - moduleName: 'SampleTurboModule', - }, - }, -}; - -// Promise is only supported by C++ (Cxx) TurboModules (see -// throwIfUnsupportedPromiseArrayBuffer), so this fixture is excluded on both -// Android and iOS. It keeps C++ codegen coverage for the async-return case. -const ARRAY_BUFFER_PROMISE_NATIVE_MODULE: SchemaType = { - modules: { - NativeSampleTurboModule: { - type: 'NativeModule', - aliasMap: {}, - enumMap: {}, - spec: { - eventEmitters: [], - methods: [ { name: 'promiseArrayBuffer', optional: false, @@ -2694,10 +2675,26 @@ const ARRAY_BUFFER_PROMISE_NATIVE_MODULE: SchemaType = { params: [], }, }, + { + name: 'promiseNullableArrayBuffer', + optional: false, + typeAnnotation: { + type: 'FunctionTypeAnnotation', + returnTypeAnnotation: { + type: 'PromiseTypeAnnotation', + elementType: { + type: 'NullableTypeAnnotation', + typeAnnotation: { + type: 'ArrayBufferTypeAnnotation', + }, + }, + }, + params: [], + }, + }, ], }, moduleName: 'SampleTurboModule', - excludedPlatforms: ['android', 'iOS'], }, }, }; @@ -2896,7 +2893,6 @@ const STRING_LITERALS: SchemaType = { module.exports = { array_buffer_native_module: ARRAY_BUFFER_NATIVE_MODULE, - array_buffer_promise_native_module: ARRAY_BUFFER_PROMISE_NATIVE_MODULE, complex_objects: COMPLEX_OBJECTS, two_modules_different_files: TWO_MODULES_DIFFERENT_FILES, empty_native_modules: EMPTY_NATIVE_MODULES, diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleHObjCpp-test.js b/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleHObjCpp-test.js index c151a4aa1cc1..bb50ae55a1ea 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleHObjCpp-test.js +++ b/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleHObjCpp-test.js @@ -10,8 +10,6 @@ 'use strict'; -import type {SchemaType} from '../../../CodegenSchema'; - const fixtures = require('../__test_fixtures__/fixtures.js'); const generator = require('../GenerateModuleObjCpp'); @@ -33,42 +31,4 @@ describe('GenerateModuleHObjCpp', () => { ).toMatchSnapshot(); }); }); - - it('throws for a method returning Promise (unsupported on iOS)', () => { - const schema: SchemaType = { - modules: { - NativeSampleTurboModule: { - type: 'NativeModule', - aliasMap: {}, - enumMap: {}, - spec: { - eventEmitters: [], - methods: [ - { - name: 'getAsyncBuffer', - optional: false, - typeAnnotation: { - type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { - type: 'PromiseTypeAnnotation', - elementType: {type: 'ArrayBufferTypeAnnotation'}, - }, - params: [], - }, - }, - ], - }, - moduleName: 'SampleTurboModule', - }, - }, - }; - expect(() => - generator.generate( - 'array_buffer_promise_throws', - schema, - 'com.facebook.fbreact.specs', - false, - ), - ).toThrow(/Promise is not supported/); - }); }); diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleJavaSpec-test.js b/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleJavaSpec-test.js index 3cbcf9747179..45d7b0e58796 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleJavaSpec-test.js +++ b/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleJavaSpec-test.js @@ -10,8 +10,6 @@ 'use strict'; -import type {SchemaType} from '../../../CodegenSchema'; - const fixtures = require('../__test_fixtures__/fixtures.js'); const generator = require('../GenerateModuleJavaSpec.js'); @@ -31,37 +29,4 @@ describe('GenerateModuleJavaSpec', () => { ).toMatchSnapshot(); }); }); - - it('throws for a method returning Promise (unsupported on Android)', () => { - const schema: SchemaType = { - modules: { - NativeSampleTurboModule: { - type: 'NativeModule', - aliasMap: {}, - enumMap: {}, - spec: { - eventEmitters: [], - methods: [ - { - name: 'getAsyncBuffer', - optional: false, - typeAnnotation: { - type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { - type: 'PromiseTypeAnnotation', - elementType: {type: 'ArrayBufferTypeAnnotation'}, - }, - params: [], - }, - }, - ], - }, - moduleName: 'SampleTurboModule', - }, - }, - }; - expect(() => - generator.generate('array_buffer_promise_throws', schema), - ).toThrow(/Promise is not supported/); - }); }); diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleJniCpp-test.js b/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleJniCpp-test.js index 72e173904c6a..0e1fae7402eb 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleJniCpp-test.js +++ b/packages/react-native-codegen/src/generators/modules/__tests__/GenerateModuleJniCpp-test.js @@ -10,8 +10,6 @@ 'use strict'; -import type {SchemaType} from '../../../CodegenSchema'; - const fixtures = require('../__test_fixtures__/fixtures.js'); const generator = require('../GenerateModuleJniCpp.js'); @@ -31,41 +29,4 @@ describe('GenerateModuleJniCpp', () => { ).toMatchSnapshot(); }); }); - - it('throws for a method returning Promise (unsupported on Android)', () => { - const schema: SchemaType = { - modules: { - NativeSampleTurboModule: { - type: 'NativeModule', - aliasMap: {}, - enumMap: {}, - spec: { - eventEmitters: [], - methods: [ - { - name: 'getAsyncBuffer', - optional: false, - typeAnnotation: { - type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { - type: 'PromiseTypeAnnotation', - elementType: {type: 'ArrayBufferTypeAnnotation'}, - }, - params: [], - }, - }, - ], - }, - moduleName: 'SampleTurboModule', - }, - }, - }; - expect(() => - generator.generate( - 'array_buffer_promise_throws', - schema, - 'com.facebook.fbreact.specs', - ), - ).toThrow(/Promise is not supported/); - }); }); diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap index f2b1d6ad49ce..2e35e312030a 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap @@ -67,6 +67,8 @@ protected: methodMap_[\\"getArrayBuffer\\"] = MethodMetadata {.argCount = 0, .invoker = __getArrayBuffer}; methodMap_[\\"voidArrayBuffer\\"] = MethodMetadata {.argCount = 1, .invoker = __voidArrayBuffer}; methodMap_[\\"voidNullableArrayBuffer\\"] = MethodMetadata {.argCount = 1, .invoker = __voidNullableArrayBuffer}; + methodMap_[\\"promiseArrayBuffer\\"] = MethodMetadata {.argCount = 0, .invoker = __promiseArrayBuffer}; + methodMap_[\\"promiseNullableArrayBuffer\\"] = MethodMetadata {.argCount = 0, .invoker = __promiseNullableArrayBuffer}; } private: @@ -92,49 +94,20 @@ private: bridging::callFromJs(rt, &T::voidNullableArrayBuffer, static_cast(&turboModule)->jsInvoker_, static_cast(&turboModule), count <= 0 || args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt).getArrayBuffer(rt)));return jsi::Value::undefined(); } -}; - -} // namespace facebook::react -", -} -`; - -exports[`GenerateModuleH can generate fixture array_buffer_promise_native_module 1`] = ` -Map { - "array_buffer_promise_native_moduleJSI.h" => "/** - * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). - * - * Do not edit this file as changes may cause incorrect behavior and will be lost - * once the code is regenerated. - * - * @generated by codegen project: GenerateModuleH.js - */ - -#pragma once - -#include -#include - -namespace facebook::react { - - -template -class JSI_EXPORT NativeSampleTurboModuleCxxSpec : public TurboModule { -public: - static constexpr std::string_view kModuleName = \\"SampleTurboModule\\"; -protected: - NativeSampleTurboModuleCxxSpec(std::shared_ptr jsInvoker) : TurboModule(std::string{NativeSampleTurboModuleCxxSpec::kModuleName}, jsInvoker) { - methodMap_[\\"promiseArrayBuffer\\"] = MethodMetadata {.argCount = 0, .invoker = __promiseArrayBuffer}; - } - -private: static jsi::Value __promiseArrayBuffer(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* /*args*/, size_t /*count*/) { static_assert( bridging::getParameterCount(&T::promiseArrayBuffer) == 1, \\"Expected promiseArrayBuffer(...) to have 1 parameters\\"); return bridging::callFromJs(rt, &T::promiseArrayBuffer, static_cast(&turboModule)->jsInvoker_, static_cast(&turboModule)); } + + static jsi::Value __promiseNullableArrayBuffer(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* /*args*/, size_t /*count*/) { + static_assert( + bridging::getParameterCount(&T::promiseNullableArrayBuffer) == 1, + \\"Expected promiseNullableArrayBuffer(...) to have 1 parameters\\"); + return bridging::callFromJs(rt, &T::promiseNullableArrayBuffer, static_cast(&turboModule)->jsInvoker_, static_cast(&turboModule)); + } }; } // namespace facebook::react diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleHObjCpp-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleHObjCpp-test.js.snap index 39ea57ca8300..2328e067cd04 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleHObjCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleHObjCpp-test.js.snap @@ -105,6 +105,10 @@ Map { - (NSMutableData *)getArrayBuffer; - (void)voidArrayBuffer:(NSData *)arg; - (void)voidNullableArrayBuffer:(NSData * _Nullable)arg; +- (void)promiseArrayBuffer:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)promiseNullableArrayBuffer:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; @end @@ -132,47 +136,6 @@ namespace facebook::react { } `; -exports[`GenerateModuleHObjCpp can generate fixture array_buffer_promise_native_module 1`] = ` -Map { - "array_buffer_promise_native_module.h" => "/** - * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). - * - * Do not edit this file as changes may cause incorrect behavior and will be lost - * once the code is regenerated. - * - * @generated by codegen project: GenerateModuleObjCpp - * - * We create an umbrella header (and corresponding implementation) here since - * Cxx compilation in BUCK has a limitation: source-code producing genrule()s - * must have a single output. More files => more genrule()s => slower builds. - */ - -#ifndef __cplusplus -#error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. -#endif - -// Avoid multiple includes of array_buffer_promise_native_module symbols -#ifndef array_buffer_promise_native_module_H -#define array_buffer_promise_native_module_H - -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - - - -#endif // array_buffer_promise_native_module_H -", -} -`; - exports[`GenerateModuleHObjCpp can generate fixture complex_objects 1`] = ` Map { "complex_objects.h" => "/** diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJavaSpec-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJavaSpec-test.js.snap index a5a124961180..d96b507a8f60 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJavaSpec-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJavaSpec-test.js.snap @@ -58,6 +58,7 @@ Map { package com.facebook.fbreact.specs; import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; @@ -89,13 +90,19 @@ public abstract class NativeSampleTurboModuleSpec extends ReactContextBaseJavaMo @ReactMethod @DoNotStrip public abstract void voidNullableArrayBuffer(@Nullable ByteBuffer arg); + + @ReactMethod + @DoNotStrip + public abstract void promiseArrayBuffer(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void promiseNullableArrayBuffer(Promise promise); } ", } `; -exports[`GenerateModuleJavaSpec can generate fixture array_buffer_promise_native_module 1`] = `Map {}`; - exports[`GenerateModuleJavaSpec can generate fixture complex_objects 1`] = ` Map { "java/com/facebook/fbreact/specs/NativeSampleTurboModuleSpec.java" => " diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniCpp-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniCpp-test.js.snap index 801fc744dac2..07fe063cb8e3 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniCpp-test.js.snap @@ -53,17 +53,27 @@ namespace facebook::react { static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getArrayBuffer(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, ArrayBufferKind, \\"getArrayBuffer\\", \\"()Ljava/nio/ByteBuffer;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, ArrayBufferKind, \\"getArrayBuffer\\", \\"()Ljava/nio/ByteBuffer;\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_voidArrayBuffer(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidArrayBuffer\\", \\"(Ljava/nio/ByteBuffer;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidArrayBuffer\\", \\"(Ljava/nio/ByteBuffer;)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_voidNullableArrayBuffer(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidNullableArrayBuffer\\", \\"(Ljava/nio/ByteBuffer;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidNullableArrayBuffer\\", \\"(Ljava/nio/ByteBuffer;)V\\", args, count, cachedMethodId, false); +} + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_promiseArrayBuffer(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"promiseArrayBuffer\\", \\"(Lcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId, true); +} + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_promiseNullableArrayBuffer(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"promiseNullableArrayBuffer\\", \\"(Lcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId, true); } NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) @@ -71,6 +81,8 @@ NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboMo methodMap_[\\"getArrayBuffer\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleSpecJSI_getArrayBuffer}; methodMap_[\\"voidArrayBuffer\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_voidArrayBuffer}; methodMap_[\\"voidNullableArrayBuffer\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_voidNullableArrayBuffer}; + methodMap_[\\"promiseArrayBuffer\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleSpecJSI_promiseArrayBuffer}; + methodMap_[\\"promiseNullableArrayBuffer\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleSpecJSI_promiseNullableArrayBuffer}; } std::shared_ptr array_buffer_native_module_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { @@ -85,34 +97,6 @@ std::shared_ptr array_buffer_native_module_ModuleProvider(const std } `; -exports[`GenerateModuleJniCpp can generate fixture array_buffer_promise_native_module 1`] = ` -Map { - "jni/array_buffer_promise_native_module-generated.cpp" => " -/** - * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). - * - * Do not edit this file as changes may cause incorrect behavior and will be lost - * once the code is regenerated. - * - * @generated by codegen project: GenerateModuleJniCpp.js - */ - -#include \\"array_buffer_promise_native_module.h\\" - -namespace facebook::react { - - - -std::shared_ptr array_buffer_promise_native_module_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { - - return nullptr; -} - -} // namespace facebook::react -", -} -`; - exports[`GenerateModuleJniCpp can generate fixture complex_objects 1`] = ` Map { "jni/complex_objects-generated.cpp" => " @@ -131,37 +115,37 @@ namespace facebook::react { static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_difficult(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"difficult\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)Lcom/facebook/react/bridge/WritableMap;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"difficult\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)Lcom/facebook/react/bridge/WritableMap;\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_optionals(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"optionals\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"optionals\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_optionalMethod(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"optionalMethod\\", \\"(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Callback;Lcom/facebook/react/bridge/ReadableArray;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"optionalMethod\\", \\"(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Callback;Lcom/facebook/react/bridge/ReadableArray;)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getArrays(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"getArrays\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"getArrays\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getNullableObject(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getNullableObject\\", \\"()Lcom/facebook/react/bridge/WritableMap;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getNullableObject\\", \\"()Lcom/facebook/react/bridge/WritableMap;\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getNullableGenericObject(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getNullableGenericObject\\", \\"()Lcom/facebook/react/bridge/WritableMap;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getNullableGenericObject\\", \\"()Lcom/facebook/react/bridge/WritableMap;\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getNullableArray(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, ArrayKind, \\"getNullableArray\\", \\"()Lcom/facebook/react/bridge/WritableArray;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, ArrayKind, \\"getNullableArray\\", \\"()Lcom/facebook/react/bridge/WritableArray;\\", args, count, cachedMethodId, false); } NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) @@ -268,7 +252,7 @@ namespace facebook::react { static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_voidFunc(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidFunc\\", \\"()V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidFunc\\", \\"()V\\", args, count, cachedMethodId, false); } NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) @@ -315,7 +299,7 @@ namespace facebook::react { static facebook::jsi::Value __hostFunction_AliasTurboModuleSpecJSI_cropImage(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"cropImage\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"cropImage\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)V\\", args, count, cachedMethodId, false); } AliasTurboModuleSpecJSI::AliasTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) @@ -355,17 +339,17 @@ namespace facebook::react { static facebook::jsi::Value __hostFunction_NativeCameraRollManagerSpecJSI_getPhotos(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"getPhotos\\", \\"(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"getPhotos\\", \\"(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeCameraRollManagerSpecJSI_saveToCameraRoll(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"saveToCameraRoll\\", \\"(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"saveToCameraRoll\\", \\"(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeCameraRollManagerSpecJSI_deletePhotos(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"deletePhotos\\", \\"(Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"deletePhotos\\", \\"(Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId, false); } NativeCameraRollManagerSpecJSI::NativeCameraRollManagerSpecJSI(const JavaTurboModule::InitParams ¶ms) @@ -376,27 +360,27 @@ NativeCameraRollManagerSpecJSI::NativeCameraRollManagerSpecJSI(const JavaTurboMo } static facebook::jsi::Value __hostFunction_NativeExceptionsManagerSpecJSI_reportFatalException(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"reportFatalException\\", \\"(Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;D)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"reportFatalException\\", \\"(Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;D)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeExceptionsManagerSpecJSI_reportSoftException(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"reportSoftException\\", \\"(Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;D)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"reportSoftException\\", \\"(Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;D)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeExceptionsManagerSpecJSI_reportException(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"reportException\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"reportException\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeExceptionsManagerSpecJSI_updateExceptionMessage(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"updateExceptionMessage\\", \\"(Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;D)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"updateExceptionMessage\\", \\"(Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;D)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeExceptionsManagerSpecJSI_dismissRedbox(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"dismissRedbox\\", \\"()V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"dismissRedbox\\", \\"()V\\", args, count, cachedMethodId, false); } NativeExceptionsManagerSpecJSI::NativeExceptionsManagerSpecJSI(const JavaTurboModule::InitParams ¶ms) @@ -441,72 +425,72 @@ namespace facebook::react { static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getConstants\\", \\"()Ljava/util/Map;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getConstants\\", \\"()Ljava/util/Map;\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_voidFunc(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidFunc\\", \\"()V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidFunc\\", \\"()V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getBool(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, BooleanKind, \\"getBool\\", \\"(Z)Z\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, BooleanKind, \\"getBool\\", \\"(Z)Z\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getNumber(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, NumberKind, \\"getNumber\\", \\"(D)D\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, NumberKind, \\"getNumber\\", \\"(D)D\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getString(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, StringKind, \\"getString\\", \\"(Ljava/lang/String;)Ljava/lang/String;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, StringKind, \\"getString\\", \\"(Ljava/lang/String;)Ljava/lang/String;\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getArray(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, ArrayKind, \\"getArray\\", \\"(Lcom/facebook/react/bridge/ReadableArray;)Lcom/facebook/react/bridge/WritableArray;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, ArrayKind, \\"getArray\\", \\"(Lcom/facebook/react/bridge/ReadableArray;)Lcom/facebook/react/bridge/WritableArray;\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getObject(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getObject\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)Lcom/facebook/react/bridge/WritableMap;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getObject\\", \\"(Lcom/facebook/react/bridge/ReadableMap;)Lcom/facebook/react/bridge/WritableMap;\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getRootTag(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, NumberKind, \\"getRootTag\\", \\"(D)D\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, NumberKind, \\"getRootTag\\", \\"(D)D\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getValue(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getValue\\", \\"(DLjava/lang/String;Lcom/facebook/react/bridge/ReadableMap;)Lcom/facebook/react/bridge/WritableMap;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getValue\\", \\"(DLjava/lang/String;Lcom/facebook/react/bridge/ReadableMap;)Lcom/facebook/react/bridge/WritableMap;\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getEnumReturn(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, NumberKind, \\"getEnumReturn\\", \\"()D\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, NumberKind, \\"getEnumReturn\\", \\"()D\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithCallback(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"getValueWithCallback\\", \\"(Lcom/facebook/react/bridge/Callback;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"getValueWithCallback\\", \\"(Lcom/facebook/react/bridge/Callback;)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithPromise(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"getValueWithPromise\\", \\"(ZLcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"getValueWithPromise\\", \\"(ZLcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithOptionalArg(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"getValueWithOptionalArg\\", \\"(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, \\"getValueWithOptionalArg\\", \\"(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId, false); } static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getEnums(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, StringKind, \\"getEnums\\", \\"(DLjava/lang/String;)Ljava/lang/String;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, StringKind, \\"getEnums\\", \\"(DLjava/lang/String;)Ljava/lang/String;\\", args, count, cachedMethodId, false); } NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) @@ -557,7 +541,7 @@ namespace facebook::react { static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getStringLiteral(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, StringKind, \\"getStringLiteral\\", \\"(Ljava/lang/String;)Ljava/lang/String;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, StringKind, \\"getStringLiteral\\", \\"(Ljava/lang/String;)Ljava/lang/String;\\", args, count, cachedMethodId, false); } NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) @@ -597,7 +581,7 @@ namespace facebook::react { static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_voidFunc(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidFunc\\", \\"()V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidFunc\\", \\"()V\\", args, count, cachedMethodId, false); } NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) @@ -608,7 +592,7 @@ NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboMo static facebook::jsi::Value __hostFunction_NativeSampleTurboModule2SpecJSI_voidFunc(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidFunc\\", \\"()V\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidFunc\\", \\"()V\\", args, count, cachedMethodId, false); } NativeSampleTurboModule2SpecJSI::NativeSampleTurboModule2SpecJSI(const JavaTurboModule::InitParams ¶ms) @@ -649,7 +633,7 @@ namespace facebook::react { static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getUnion(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { static jmethodID cachedMethodId = nullptr; - return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getUnion\\", \\"(DDLcom/facebook/react/bridge/ReadableMap;Ljava/lang/String;Ljava/lang/String;)Lcom/facebook/react/bridge/ReadableMap;\\", args, count, cachedMethodId); + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getUnion\\", \\"(DDLcom/facebook/react/bridge/ReadableMap;Ljava/lang/String;Ljava/lang/String;)Lcom/facebook/react/bridge/ReadableMap;\\", args, count, cachedMethodId, false); } NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniH-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniH-test.js.snap index fed0ac2033fd..daa41686b1c4 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniH-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniH-test.js.snap @@ -132,65 +132,6 @@ target_compile_reactnative_options(react_codegen_array_buffer_native_module PRIV } `; -exports[`GenerateModuleJniH can generate fixture array_buffer_promise_native_module 1`] = ` -Map { - "jni/array_buffer_promise_native_module.h" => " -/** - * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). - * - * Do not edit this file as changes may cause incorrect behavior and will be lost - * once the code is regenerated. - * - * @generated by codegen project: GenerateModuleJniH.js - */ - -#pragma once - -#include -#include -#include - -namespace facebook::react { - - - -JSI_EXPORT -std::shared_ptr array_buffer_promise_native_module_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); - -} // namespace facebook::react -", - "jni/CMakeLists.txt" => "# 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. - -cmake_minimum_required(VERSION 3.13) -set(CMAKE_VERBOSE_MAKEFILE on) - -file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/array_buffer_promise_native_module/*.cpp) - -add_library( - react_codegen_array_buffer_promise_native_module - OBJECT - \${react_codegen_SRCS} -) - -target_include_directories(react_codegen_array_buffer_promise_native_module PUBLIC . react/renderer/components/array_buffer_promise_native_module) - -target_link_libraries( - react_codegen_array_buffer_promise_native_module - fbjni - jsi - # We need to link different libraries based on whether we are building rncore or not, that's necessary - # because we want to break a circular dependency between react_codegen_rncore and reactnative - reactnative -) - -target_compile_reactnative_options(react_codegen_array_buffer_promise_native_module PRIVATE) -", -} -`; - exports[`GenerateModuleJniH can generate fixture complex_objects 1`] = ` Map { "jni/complex_objects.h" => " diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleMm-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleMm-test.js.snap index c2b1cf853c45..8a7c8c2aca9a 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleMm-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleMm-test.js.snap @@ -82,6 +82,14 @@ namespace facebook::react { return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, \\"voidNullableArrayBuffer\\", @selector(voidNullableArrayBuffer:), args, count); } + static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_promiseArrayBuffer(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, \\"promiseArrayBuffer\\", @selector(promiseArrayBuffer:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_promiseNullableArrayBuffer(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, \\"promiseNullableArrayBuffer\\", @selector(promiseNullableArrayBuffer:reject:), args, count); + } + NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms) : ObjCTurboModule(params) { @@ -93,34 +101,18 @@ namespace facebook::react { methodMap_[\\"voidNullableArrayBuffer\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_voidNullableArrayBuffer}; + + methodMap_[\\"promiseArrayBuffer\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleSpecJSI_promiseArrayBuffer}; + + + methodMap_[\\"promiseNullableArrayBuffer\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleSpecJSI_promiseNullableArrayBuffer}; + } } // namespace facebook::react ", } `; -exports[`GenerateModuleMm can generate fixture array_buffer_promise_native_module 1`] = ` -Map { - "array_buffer_promise_native_module-generated.mm" => "/** - * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). - * - * Do not edit this file as changes may cause incorrect behavior and will be lost - * once the code is regenerated. - * - * @generated by codegen project: GenerateModuleObjCpp - * - * We create an umbrella header (and corresponding implementation) here since - * Cxx compilation in BUCK has a limitation: source-code producing genrule()s - * must have a single output. More files => more genrule()s => slower builds. - */ - -#import \\"array_buffer_promise_native_module.h\\" - - -", -} -`; - exports[`GenerateModuleMm can generate fixture complex_objects 1`] = ` Map { "complex_objects-generated.mm" => "/** diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CxxArrayBufferCallbackImpl.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CxxArrayBufferCallbackImpl.kt new file mode 100644 index 000000000000..c04b9ba1f3e8 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/CxxArrayBufferCallbackImpl.kt @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package com.facebook.react.bridge + +import com.facebook.jni.HybridClassBase +import com.facebook.proguard.annotations.DoNotStrip +import java.nio.ByteBuffer + +/** + * Resolve callback for a Promise that may be fulfilled with an `ArrayBuffer` or null. Created from + * C++ only where the JavaScript spec permits `Promise` or `Promise`. + * + * Unlike [CxxCallbackImpl], this does not serialize through folly::dynamic. A direct [ByteBuffer] + * reaches JavaScript aliasing the same memory; null is forwarded explicitly. + * + * A module that resolves with anything else is misusing its spec. Rather than throwing on whichever + * thread called `Promise.resolve`, the problem is described to C++, which rejects the Promise with + * it. + */ +@DoNotStrip +internal class CxxArrayBufferCallbackImpl @DoNotStrip private constructor() : + HybridClassBase(), Callback { + + override fun invoke(vararg args: Any?) { + if (args.size > 1) { + nativeInvoke(null, "expected at most one argument, got ${args.size}") + return + } + when (val arg = args.firstOrNull()) { + null -> nativeInvoke(null, null) + is ByteBuffer -> + if (arg.isDirect) { + nativeInvoke(arg, null) + } else { + nativeInvoke(null, "expected a direct ByteBuffer (ByteBuffer.allocateDirect)") + } + else -> nativeInvoke(null, "expected a ByteBuffer or null, got ${arg.javaClass.name}") + } + } + + /** At most one of [buffer] and [error] is non-null. Both null resolves with JavaScript null. */ + private external fun nativeInvoke(buffer: ByteBuffer?, error: String?) +} diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JArrayBufferCallback.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JArrayBufferCallback.h new file mode 100644 index 000000000000..13a55ee95e4a --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JArrayBufferCallback.h @@ -0,0 +1,60 @@ +/* + * 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 + +#include "JCallback.h" + +namespace facebook::react { + +// Resolve callback for a Promise that may be fulfilled with an ArrayBuffer or null. +// +// Created only where the JavaScript spec permits Promise or +// Promise. Does not use folly::dynamic; a non-null ArrayBuffer is +// handed to JavaScript without copying, and null is forwarded explicitly. +// +// The Java side validates what the module resolved with and reports a +// description of the problem through `error` instead of throwing, so that +// misuse rejects the Promise rather than escaping on the resolving thread. +class JCxxArrayBufferCallbackImpl : public jni::HybridClass { + public: + constexpr static auto kJavaDescriptor = "Lcom/facebook/react/bridge/CxxArrayBufferCallbackImpl;"; + + static void registerNatives() + { + registerHybrid({ + makeNativeMethod("nativeInvoke", JCxxArrayBufferCallbackImpl::invoke), + }); + } + + private: + friend HybridBase; + + // At most one of `arrayBuffer` and `error` is non-null. Both null resolves + // the Promise with JavaScript null. + using Callback = std::function arrayBuffer, + jni::alias_ref error)>; + + explicit JCxxArrayBufferCallbackImpl(Callback callback) : callback_(std::move(callback)) {} + + void invoke( + jni::alias_ref arrayBuffer, + jni::alias_ref error) + { + callback_(arrayBuffer, error); + } + + Callback callback_; +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp index 293d2ffc8abf..e984112fcf7c 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp @@ -6,6 +6,7 @@ */ #include +#include "JArrayBufferCallback.h" #include "JCallback.h" #include "JDynamicNative.h" #include "JReactMarker.h" @@ -18,6 +19,7 @@ namespace facebook::react { extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { return facebook::jni::initialize(vm, [] { + JCxxArrayBufferCallbackImpl::registerNatives(); JCxxCallbackImpl::registerNatives(); JDynamicNative::registerNatives(); JReactMarker::registerNatives(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp index cec9eaf5f02d..51716dfd9c84 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -117,48 +119,152 @@ jsi::Value createRejectionError(jsi::Runtime& rt, const folly::dynamic& args) { return jsError; } -auto createJavaCallback( +class OnceCallback { + std::optional> callback_; + + public: + OnceCallback( + jsi::Runtime& rt, + jsi::Function function, + std::shared_ptr jsInvoker) + : callback_(AsyncCallback<>(rt, std::move(function), std::move(jsInvoker))) {} + + OnceCallback(const OnceCallback&) = delete; + OnceCallback& operator=(const OnceCallback&) = delete; + OnceCallback(OnceCallback&&) = default; + OnceCallback& operator=(OnceCallback&&) = default; + + template + void call(const char* what, F&& invoke) { + if (!callback_) { + LOG(FATAL) << what << " cannot be called more than once"; + return; + } + callback_->call(std::forward(invoke)); + callback_ = std::nullopt; + } + + void callWithArgs(const char* what, folly::dynamic&& args) noexcept { + call(what, [args = std::move(args)]( + jsi::Runtime& rt, jsi::Function& jsFunction) mutable { + std::vector jsArgs; + jsArgs.reserve(args.size()); + for (const auto& val : args) { + jsArgs.emplace_back(jsi::valueFromDynamic(rt, val)); + } + jsFunction.call(rt, (const jsi::Value*)jsArgs.data(), jsArgs.size()); + }); + } +}; + +template +jni::local_ref makeJavaOnceCallback( + jsi::Runtime& rt, + jsi::Function function, + std::shared_ptr jsInvoker, + Handler handler) { + auto once = std::make_shared( + rt, std::move(function), std::move(jsInvoker)); + return jni::static_ref_cast( + JavaCallbackImpl::newObjectCxxArgs( + [once = std::move(once), + handler = std::move(handler)](auto&&... args) mutable { + handler(*once, std::forward(args)...); + })); +} + +jni::local_ref createJavaCallback( jsi::Runtime& rt, jsi::Function&& function, std::shared_ptr jsInvoker) { - std::optional> callback( - {rt, std::move(function), std::move(jsInvoker)}); - return JCxxCallbackImpl::newObjectCxxArgs( - [callback = std::move(callback)](folly::dynamic args) mutable { - if (!callback) { - LOG(FATAL) << "Callback arg cannot be called more than once"; + return makeJavaOnceCallback( + rt, + std::move(function), + std::move(jsInvoker), + [](OnceCallback& once, folly::dynamic args) { + once.callWithArgs("Callback arg", std::move(args)); + }); +} + +jni::local_ref createJavaArrayBufferCallback( + jsi::Runtime& rt, + jsi::Function&& resolveFunction, + jsi::Function&& rejectFunction, + std::shared_ptr jsInvoker) { + auto rejectMisuse = + std::make_shared(rt, std::move(rejectFunction), jsInvoker); + return makeJavaOnceCallback( + rt, + std::move(resolveFunction), + std::move(jsInvoker), + [rejectMisuse = std::move(rejectMisuse)]( + OnceCallback& once, + jni::alias_ref buffer, + jni::alias_ref error) { + if (error) { + rejectMisuse->call( + "Promise reject", + [message = "Invalid Promise resolution: " + + error->toStdString()]( + jsi::Runtime& rt, jsi::Function& jsFunction) { + jsFunction.call(rt, createJSRuntimeError(rt, message)); + }); return; } - callback->call([args = std::move(args)]( - jsi::Runtime& rt, jsi::Function& jsFunction) { - std::vector jsArgs; - jsArgs.reserve(args.size()); - for (const auto& val : args) { - jsArgs.emplace_back(jsi::valueFromDynamic(rt, val)); - } - jsFunction.call(rt, (const jsi::Value*)jsArgs.data(), jsArgs.size()); - }); - callback = std::nullopt; + + jni::global_ref globalBuffer; + if (buffer) { + globalBuffer = jni::make_global(buffer); + } + + once.call( + "Promise resolve", + [globalBuffer = std::move(globalBuffer)]( + jsi::Runtime& rt, jsi::Function& jsFunction) { + if (!globalBuffer) { + jsFunction.call(rt, jsi::Value::null()); + return; + } + + auto nativeBuffer = + std::make_shared(globalBuffer); + jsFunction.call( + rt, + jsi::Value(jsi::ArrayBuffer(rt, std::move(nativeBuffer)))); + }); }); } -auto createJavaRejectCallback( +jni::local_ref createJavaResolveCallback( + jsi::Runtime& rt, + jsi::Function&& resolveFunction, + jsi::Function&& rejectFunction, + std::shared_ptr jsInvoker, + bool promiseResolveSupportsArrayBuffer) { + return promiseResolveSupportsArrayBuffer + ? createJavaArrayBufferCallback( + rt, + std::move(resolveFunction), + std::move(rejectFunction), + std::move(jsInvoker)) + : createJavaCallback( + rt, std::move(resolveFunction), std::move(jsInvoker)); +} + +jni::local_ref createJavaRejectCallback( jsi::Runtime& rt, jsi::Function&& function, std::shared_ptr jsInvoker) { - std::optional> callback( - {rt, std::move(function), std::move(jsInvoker)}); - return JCxxCallbackImpl::newObjectCxxArgs( - [callback = std::move(callback)](folly::dynamic args) mutable { - if (!callback) { - LOG(FATAL) << "Callback arg cannot be called more than once"; - return; - } - callback->call([args = std::move(args)]( - jsi::Runtime& rt, jsi::Function& jsFunction) { + return makeJavaOnceCallback( + rt, + std::move(function), + std::move(jsInvoker), + [](OnceCallback& once, folly::dynamic args) { + once.call("Promise reject", [args = std::move(args)]( + jsi::Runtime& rt, + jsi::Function& jsFunction) { jsFunction.call(rt, createRejectionError(rt, args)); }); - callback = std::nullopt; }); } @@ -555,7 +661,11 @@ jsi::Value JavaTurboModule::invokeJavaMethod( const std::string& methodSignature, const jsi::Value* args, size_t argCount, - jmethodID& methodID) { + jmethodID& methodID, + bool promiseResolveSupportsArrayBuffer) { + react_native_assert( + !promiseResolveSupportsArrayBuffer || valueKind == PromiseKind); + const char* methodName = methodNameStr.c_str(); const char* moduleName = name_.c_str(); @@ -919,10 +1029,12 @@ jsi::Value JavaTurboModule::invokeJavaMethod( args[1].getObject(runtime).getFunction(runtime), jsInvoker_); - auto resolve = createJavaCallback( + auto resolve = createJavaResolveCallback( runtime, args[0].getObject(runtime).getFunction(runtime), - jsInvoker_); + args[1].getObject(runtime).getFunction(runtime), + jsInvoker_, + promiseResolveSupportsArrayBuffer); auto reject = createJavaRejectCallback( runtime, args[1].getObject(runtime).getFunction(runtime), diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.h b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.h index c42f1c7dbac0..e2c8dd777917 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.h +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.h @@ -45,7 +45,8 @@ class JSI_EXPORT JavaTurboModule : public TurboModule { const std::string &methodSignature, const jsi::Value *args, size_t argCount, - jmethodID &cachedMethodID); + jmethodID &cachedMethodID, + bool promiseResolveSupportsArrayBuffer = false); protected: void configureEventEmitterCallback(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/samples/platform/android/SampleTurboModule.kt b/packages/react-native/ReactCommon/react/nativemodule/samples/platform/android/SampleTurboModule.kt index c8a36acc32b0..6be84047528c 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/samples/platform/android/SampleTurboModule.kt +++ b/packages/react-native/ReactCommon/react/nativemodule/samples/platform/android/SampleTurboModule.kt @@ -179,6 +179,24 @@ public class SampleTurboModule(private val context: ReactApplicationContext) : promise.resolve((payload?.capacity() ?: 0).toDouble()) } + @DoNotStrip + @Suppress("unused") + override fun getAsyncBuffer(size: Double, promise: Promise) { + if (!size.isFinite() || size < 0.0 || size > Int.MAX_VALUE.toDouble()) { + promise.reject( + "invalid_size", + "getAsyncBuffer: size must be a finite value in [0, ${Int.MAX_VALUE}], got $size") + return + } + val capacity = size.toInt() + val buffer = ByteBuffer.allocateDirect(capacity) + for (i in 0 until capacity) { + buffer.put(i, (i + 1).toByte()) + } + log("getAsyncBuffer", size, buffer) + promise.resolve(buffer) + } + @DoNotStrip @Suppress("unused") override fun getValueWithCallback(callback: Callback?) { diff --git a/packages/react-native/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTSampleTurboModule.mm b/packages/react-native/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTSampleTurboModule.mm index e2b9d4bf42c9..dd269dfdd77f 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTSampleTurboModule.mm +++ b/packages/react-native/ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTSampleTurboModule.mm @@ -14,6 +14,8 @@ #import #import +#include + using namespace facebook::react; @interface RCTSampleTurboModule () @@ -165,6 +167,23 @@ - (void)processAsyncBuffer:(NSData *)payload resolve(@(payload.length)); } +// Resolving a Promise with an NSMutableData hands JS the bytes without copying +// them; the object keeps them alive for as long as JS holds the ArrayBuffer. +- (void)getAsyncBuffer:(double)size resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject +{ + if (!std::isfinite(size) || size < 0 || size > (double)NSUIntegerMax) { + reject(@"invalid_size", [NSString stringWithFormat:@"getAsyncBuffer: invalid size %g", size], nil); + return; + } + + NSMutableData *buffer = [NSMutableData dataWithLength:(NSUInteger)size]; + uint8_t *bytes = static_cast(buffer.mutableBytes); + for (NSUInteger i = 0; i < buffer.length; i++) { + bytes[i] = static_cast(i + 1); + } + resolve(buffer); +} + - (void)getValueWithCallback:(RCTResponseSenderBlock)callback { if (callback == nullptr) { diff --git a/packages/react-native/src/private/specs_DEPRECATED/modules/NativeSampleTurboModule.js b/packages/react-native/src/private/specs_DEPRECATED/modules/NativeSampleTurboModule.js index c458c91a2204..3f4b77c4801c 100644 --- a/packages/react-native/src/private/specs_DEPRECATED/modules/NativeSampleTurboModule.js +++ b/packages/react-native/src/private/specs_DEPRECATED/modules/NativeSampleTurboModule.js @@ -54,6 +54,7 @@ export interface Spec extends TurboModule { readonly getArrayBuffer: (buffer: ArrayBuffer) => ArrayBuffer; readonly createNativeBuffer: (size: number) => ArrayBuffer; readonly processAsyncBuffer: (payload: ArrayBuffer) => Promise; + readonly getAsyncBuffer: (size: number) => Promise; readonly getValueWithCallback: (callback: (value: string) => void) => void; readonly getValueWithPromise: (error: boolean) => Promise; readonly voidFuncThrows?: () => void; diff --git a/packages/rn-tester/js/examples/TurboModule/SampleTurboModuleExample.js b/packages/rn-tester/js/examples/TurboModule/SampleTurboModuleExample.js index f7e8373a995a..f546a63b1d40 100644 --- a/packages/rn-tester/js/examples/TurboModule/SampleTurboModuleExample.js +++ b/packages/rn-tester/js/examples/TurboModule/SampleTurboModuleExample.js @@ -49,6 +49,7 @@ type Examples = | 'getArrayBuffer' | 'createNativeBuffer' | 'processAsyncBuffer' + | 'getAsyncBuffer' | 'promise' | 'rejectPromise' | 'voidFunc' @@ -122,6 +123,10 @@ class SampleTurboModuleExample extends React.Component<{}, State> { NativeSampleTurboModule.processAsyncBuffer( new Uint8Array([1, 2, 3]).buffer, ).then(length => this._setResult('processAsyncBuffer', length)), + getAsyncBuffer: () => + NativeSampleTurboModule.getAsyncBuffer(4).then(buffer => + this._setResult('getAsyncBuffer', Array.from(new Uint8Array(buffer))), + ), }; // $FlowFixMe[missing-local-annot] diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api index 5588b49856fe..288b6fade86f 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api @@ -2808,6 +2808,11 @@ class facebook::react::JByteBufferMutableBuffer : public facebook::jsi::MutableB public ~JByteBufferMutableBuffer() override; } +class facebook::react::JCxxArrayBufferCallbackImpl : public jni::HybridClass { + public static constexpr auto kJavaDescriptor; + public static void registerNatives(); +} + class facebook::react::JCxxCallbackImpl : public jni::HybridClass { public static constexpr auto kJavaDescriptor; public static void registerNatives(); @@ -3083,7 +3088,7 @@ class facebook::react::JavaTurboModule : public facebook::react::TurboModule { protected void configureEventEmitterCallback(); protected void setEventEmitterCallback(jni::alias_ref); public JavaTurboModule(const facebook::react::JavaTurboModule::InitParams& params); - public facebook::jsi::Value invokeJavaMethod(facebook::jsi::Runtime& runtime, facebook::react::TurboModuleMethodValueKind valueKind, const std::string& methodName, const std::string& methodSignature, const facebook::jsi::Value* args, size_t argCount, jmethodID& cachedMethodID); + public facebook::jsi::Value invokeJavaMethod(facebook::jsi::Runtime& runtime, facebook::react::TurboModuleMethodValueKind valueKind, const std::string& methodName, const std::string& methodSignature, const facebook::jsi::Value* args, size_t argCount, jmethodID& cachedMethodID, bool promiseResolveSupportsArrayBuffer = false); public virtual ~JavaTurboModule(); } diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api index 3f4f51314fa2..0aaf7234747a 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api @@ -2766,6 +2766,11 @@ class facebook::react::JByteBufferMutableBuffer : public facebook::jsi::MutableB public ~JByteBufferMutableBuffer() override; } +class facebook::react::JCxxArrayBufferCallbackImpl : public jni::HybridClass { + public static constexpr auto kJavaDescriptor; + public static void registerNatives(); +} + class facebook::react::JCxxCallbackImpl : public jni::HybridClass { public static constexpr auto kJavaDescriptor; public static void registerNatives(); @@ -3002,7 +3007,7 @@ class facebook::react::JavaTurboModule : public facebook::react::TurboModule { protected void configureEventEmitterCallback(); protected void setEventEmitterCallback(jni::alias_ref); public JavaTurboModule(const facebook::react::JavaTurboModule::InitParams& params); - public facebook::jsi::Value invokeJavaMethod(facebook::jsi::Runtime& runtime, facebook::react::TurboModuleMethodValueKind valueKind, const std::string& methodName, const std::string& methodSignature, const facebook::jsi::Value* args, size_t argCount, jmethodID& cachedMethodID); + public facebook::jsi::Value invokeJavaMethod(facebook::jsi::Runtime& runtime, facebook::react::TurboModuleMethodValueKind valueKind, const std::string& methodName, const std::string& methodSignature, const facebook::jsi::Value* args, size_t argCount, jmethodID& cachedMethodID, bool promiseResolveSupportsArrayBuffer = false); public virtual ~JavaTurboModule(); } diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api index d3a8f1993493..c920b3ca731f 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api @@ -2805,6 +2805,11 @@ class facebook::react::JByteBufferMutableBuffer : public facebook::jsi::MutableB public ~JByteBufferMutableBuffer() override; } +class facebook::react::JCxxArrayBufferCallbackImpl : public jni::HybridClass { + public static constexpr auto kJavaDescriptor; + public static void registerNatives(); +} + class facebook::react::JCxxCallbackImpl : public jni::HybridClass { public static constexpr auto kJavaDescriptor; public static void registerNatives(); @@ -3080,7 +3085,7 @@ class facebook::react::JavaTurboModule : public facebook::react::TurboModule { protected void configureEventEmitterCallback(); protected void setEventEmitterCallback(jni::alias_ref); public JavaTurboModule(const facebook::react::JavaTurboModule::InitParams& params); - public facebook::jsi::Value invokeJavaMethod(facebook::jsi::Runtime& runtime, facebook::react::TurboModuleMethodValueKind valueKind, const std::string& methodName, const std::string& methodSignature, const facebook::jsi::Value* args, size_t argCount, jmethodID& cachedMethodID); + public facebook::jsi::Value invokeJavaMethod(facebook::jsi::Runtime& runtime, facebook::react::TurboModuleMethodValueKind valueKind, const std::string& methodName, const std::string& methodSignature, const facebook::jsi::Value* args, size_t argCount, jmethodID& cachedMethodID, bool promiseResolveSupportsArrayBuffer = false); public virtual ~JavaTurboModule(); } diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index 225cad4e1df4..f9ee54d8d1f6 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -2511,6 +2511,7 @@ protocol NativeSampleTurboModuleSpec : public NSObjectRCTBridgeModule, public RC public virtual NSString* getString:(NSString* arg); public virtual facebook::react::ModuleConstants constantsToExport(); public virtual facebook::react::ModuleConstants getConstants(); + public virtual void getAsyncBuffer:resolve:reject:(double size, RCTPromiseResolveBlock resolve, RCTPromiseRejectBlock reject); public virtual void getImageUrl:reject:(RCTPromiseResolveBlock resolve, RCTPromiseRejectBlock reject); public virtual void getValueWithCallback:(RCTResponseSenderBlock callback); public virtual void getValueWithPromise:resolve:reject:(BOOL error, RCTPromiseResolveBlock resolve, RCTPromiseRejectBlock reject); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api index 5beeba82b5b1..361ce1453125 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api @@ -2504,6 +2504,7 @@ protocol NativeSampleTurboModuleSpec : public NSObjectRCTBridgeModule, public RC public virtual NSString* getString:(NSString* arg); public virtual facebook::react::ModuleConstants constantsToExport(); public virtual facebook::react::ModuleConstants getConstants(); + public virtual void getAsyncBuffer:resolve:reject:(double size, RCTPromiseResolveBlock resolve, RCTPromiseRejectBlock reject); public virtual void getImageUrl:reject:(RCTPromiseResolveBlock resolve, RCTPromiseRejectBlock reject); public virtual void getValueWithCallback:(RCTResponseSenderBlock callback); public virtual void getValueWithPromise:resolve:reject:(BOOL error, RCTPromiseResolveBlock resolve, RCTPromiseRejectBlock reject); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index bf60fe2808aa..9854c219477a 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -2511,6 +2511,7 @@ protocol NativeSampleTurboModuleSpec : public NSObjectRCTBridgeModule, public RC public virtual NSString* getString:(NSString* arg); public virtual facebook::react::ModuleConstants constantsToExport(); public virtual facebook::react::ModuleConstants getConstants(); + public virtual void getAsyncBuffer:resolve:reject:(double size, RCTPromiseResolveBlock resolve, RCTPromiseRejectBlock reject); public virtual void getImageUrl:reject:(RCTPromiseResolveBlock resolve, RCTPromiseRejectBlock reject); public virtual void getValueWithCallback:(RCTResponseSenderBlock callback); public virtual void getValueWithPromise:resolve:reject:(BOOL error, RCTPromiseResolveBlock resolve, RCTPromiseRejectBlock reject);