diff --git a/Libraries/TurboModule/samples/NativeSampleTurboModule.js b/Libraries/TurboModule/samples/NativeSampleTurboModule.js new file mode 100644 index 00000000000..cbc8db0c576 --- /dev/null +++ b/Libraries/TurboModule/samples/NativeSampleTurboModule.js @@ -0,0 +1,34 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import {getEnforcing} from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + // Exported methods. + +getConstants: () => {| + const1: boolean, + const2: number, + const3: string, + |}; + +voidFunc: () => void; + +getBool: (arg: boolean) => boolean; + +getNumber: (arg: number) => number; + +getString: (arg: string) => string; + +getArray: (arg: Array) => Array; + +getObject: (arg: Object) => Object; + +getValue: (x: number, y: string, z: Object) => Object; + +getValueWithCallback: (callback: (value: string) => void) => void; + +getValueWithPromise: (error: boolean) => Promise; +} + +export default getEnforcing('SampleTurboModule'); diff --git a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm index 1a5e001ae5f..54afb7b31b6 100644 --- a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm +++ b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm @@ -173,7 +173,9 @@ static Class getFallbackClassFromName(const char *name) { Class moduleClass; if ([_delegate respondsToSelector:@selector(getModuleClassFromName:)]) { moduleClass = [_delegate getModuleClassFromName:moduleName]; - } else { + } + + if (!moduleClass) { moduleClass = getFallbackClassFromName(moduleName); } diff --git a/ReactCommon/turbomodule/samples/BUCK b/ReactCommon/turbomodule/samples/BUCK new file mode 100644 index 00000000000..a2f37ce69d8 --- /dev/null +++ b/ReactCommon/turbomodule/samples/BUCK @@ -0,0 +1,77 @@ +load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "OBJC_ARC_PREPROCESSOR_FLAGS", "get_debug_preprocessor_flags", "get_static_library_ios_flags") +load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob") + +rn_xplat_cxx_library( + name = "samples", + srcs = glob(["*.cpp"]), + header_namespace = "", + exported_headers = subdir_glob( + [ + ("", "*.h"), + ], + prefix = "jsireact", + ), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + fbandroid_deps = [ + react_native_target("jni/react/jni:jni"), + ], + fbandroid_exported_headers = subdir_glob( + [ + ("platform/android", "*.h"), + ], + prefix = "jsireact", + ), + fbandroid_srcs = glob( + [ + "platform/android/**/*.cpp", + ], + ), + fbobjc_compiler_flags = [ + "-Wall", + "-fobjc-arc-exceptions", + ], + fbobjc_inherited_buck_flags = get_static_library_ios_flags(), + fbobjc_preprocessor_flags = OBJC_ARC_PREPROCESSOR_FLAGS + get_debug_preprocessor_flags(), + force_static = True, + ios_deps = [ + "fbsource//xplat/FBBaseLite:FBBaseLite", + "fbsource//xplat/js/react-native-github:RCTCxxBridge", + "fbsource//xplat/js/react-native-github:RCTCxxModule", + "fbsource//xplat/js/react-native-github:ReactInternal", + ], + ios_exported_headers = subdir_glob( + [ + ("platform/ios", "*.h"), + ], + prefix = "jsireact", + ), + ios_frameworks = [ + "$SDKROOT/System/Library/Frameworks/Foundation.framework", + ], + ios_srcs = glob( + [ + "platform/ios/**/*.cpp", + "platform/ios/**/*.mm", + ], + ), + platforms = (ANDROID, APPLE), + preprocessor_flags = [ + "-DLOG_TAG=\"ReactNative\"", + "-DWITH_FBSYSTRACE=1", + ], + visibility = [ + "PUBLIC", + ], + deps = [ + react_native_xplat_target("cxxreact:module"), + ], + exported_deps = [ + "fbsource//xplat/jsi:jsi", + react_native_xplat_target("turbomodule/core:core"), + ], +) diff --git a/ReactCommon/turbomodule/samples/platform/ios/NativeSampleTurboCxxModuleSpecJSI.cpp b/ReactCommon/turbomodule/samples/platform/ios/NativeSampleTurboCxxModuleSpecJSI.cpp new file mode 100644 index 00000000000..3f591043466 --- /dev/null +++ b/ReactCommon/turbomodule/samples/platform/ios/NativeSampleTurboCxxModuleSpecJSI.cpp @@ -0,0 +1,74 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "NativeSampleTurboCxxModuleSpecJSI.h" + +// NOTE: This entire file should be codegen'ed. + +namespace facebook { +namespace react { + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return jsi::Value(static_cast(&turboModule)->getBool(rt, args[0].getBool())); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return jsi::Value(static_cast(&turboModule)->getNumber(rt, args[0].getNumber())); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getString(rt, args[0].getString(rt)); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArray(rt, args[0].getObject(rt).getArray(rt)); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObject(rt, args[0].getObject(rt)); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValue(rt, args[0].getNumber(), args[1].getString(rt), args[2].getObject(rt)); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, std::move(args[0].getObject(rt).getFunction(rt))); + return jsi::Value::undefined(); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromise(rt, args[0].getBool()); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} + +NativeSampleTurboCxxModuleSpecJSI::NativeSampleTurboCxxModuleSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("SampleTurboCxxModule", jsInvoker) { + + methodMap_["voidFunc"] = MethodMetadata {0, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_voidFunc}; + methodMap_["getBool"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getBool}; + methodMap_["getNumber"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getNumber}; + methodMap_["getString"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getString}; + methodMap_["getArray"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getArray}; + methodMap_["getObject"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getObject}; + methodMap_["getValue"] = MethodMetadata {3, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValue}; + methodMap_["getValueWithCallback"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValueWithCallback}; + methodMap_["getValueWithPromise"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValueWithPromise}; + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getConstants}; + +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/turbomodule/samples/platform/ios/NativeSampleTurboCxxModuleSpecJSI.h b/ReactCommon/turbomodule/samples/platform/ios/NativeSampleTurboCxxModuleSpecJSI.h new file mode 100644 index 00000000000..a10fcf6cca1 --- /dev/null +++ b/ReactCommon/turbomodule/samples/platform/ios/NativeSampleTurboCxxModuleSpecJSI.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its 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 { +namespace react { + +// TODO: This definition should be codegen'ed for type-safety purpose. +class JSI_EXPORT NativeSampleTurboCxxModuleSpecJSI : public TurboModule { +protected: + NativeSampleTurboCxxModuleSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void voidFunc(jsi::Runtime &rt) = 0; + virtual bool getBool(jsi::Runtime &rt, bool arg) = 0; + virtual double getNumber(jsi::Runtime &rt, double arg) = 0; + virtual jsi::String getString(jsi::Runtime &rt, const jsi::String &arg) = 0; + virtual jsi::Array getArray(jsi::Runtime &rt, const jsi::Array &arg) = 0; + virtual jsi::Object getObject(jsi::Runtime &rt, const jsi::Object &arg) = 0; + virtual jsi::Object getValue(jsi::Runtime &rt, double x, const jsi::String &y, const jsi::Object &z) = 0; + virtual void getValueWithCallback(jsi::Runtime &rt, const jsi::Function &callback) = 0; + virtual jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) = 0; + virtual jsi::Object getConstants(jsi::Runtime &rt) = 0; + +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/turbomodule/samples/platform/ios/RCTNativeSampleTurboModuleSpec.h b/ReactCommon/turbomodule/samples/platform/ios/RCTNativeSampleTurboModuleSpec.h new file mode 100644 index 00000000000..c5fb59f6d4f --- /dev/null +++ b/ReactCommon/turbomodule/samples/platform/ios/RCTNativeSampleTurboModuleSpec.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// NOTE: This entire file should be codegen'ed. + +#import + +#import + +#import +#import + +/** + * The ObjC protocol based on the JS Flow type for SampleTurboModule. + */ +@protocol NativeSampleTurboModuleSpec + +- (void)voidFunc; +- (NSNumber *)getBool:(BOOL)arg; +- (NSNumber *)getNumber:(double)arg; +- (NSString *)getString:(NSString *)arg; +- (NSArray> *)getArray:(NSArray *)arg; +- (NSDictionary *)getObject:(NSDictionary *)arg; +- (NSDictionary *)getValue:(double)x + y:(NSString *)y + z:(NSDictionary *)z; +- (void)getValueWithCallback:(RCTResponseSenderBlock)callback; +- (void)getValueWithPromise:(BOOL)error + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (NSDictionary *)constantsToExport; +- (NSDictionary *)getConstants; + +@end + +namespace facebook { +namespace react { + +/** + * The iOS TurboModule impl specific to SampleTurboModule. + */ +class JSI_EXPORT NativeSampleTurboModuleSpecJSI : public ObjCTurboModule { +public: + NativeSampleTurboModuleSpecJSI(id instance, std::shared_ptr jsInvoker); +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/turbomodule/samples/platform/ios/RCTNativeSampleTurboModuleSpec.mm b/ReactCommon/turbomodule/samples/platform/ios/RCTNativeSampleTurboModuleSpec.mm new file mode 100644 index 00000000000..1e9272fd230 --- /dev/null +++ b/ReactCommon/turbomodule/samples/platform/ios/RCTNativeSampleTurboModuleSpec.mm @@ -0,0 +1,68 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTNativeSampleTurboModuleSpec.h" + +namespace facebook { +namespace react { + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_voidFunc(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return turboModule.invokeMethod(rt, VoidKind, "voidFunc", args, count); +} + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getBool(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return turboModule.invokeMethod(rt, BooleanKind, "getBool", args, count); +} + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getNumber(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return turboModule.invokeMethod(rt, NumberKind, "getNumber", args, count); +} + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getString(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return turboModule.invokeMethod(rt, StringKind, "getString", args, count); +} + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getArray(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return turboModule.invokeMethod(rt, ArrayKind, "getArray", args, count); +} + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getObject(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return turboModule.invokeMethod(rt, ObjectKind, "getObject", args, count); +} + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getValue(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return turboModule.invokeMethod(rt, ObjectKind, "getValue", args, count); +} + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithCallback(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return turboModule.invokeMethod(rt, VoidKind, "getValueWithCallback", args, count); +} + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithPromise(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return turboModule.invokeMethod(rt, PromiseKind, "getValueWithPromise", args, count); +} + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return turboModule.invokeMethod(rt, ObjectKind, "getConstants", args, count); +} + +NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(id instance, std::shared_ptr jsInvoker) + : ObjCTurboModule("SampleTurboModule", instance, jsInvoker) { + methodMap_["voidFunc"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleSpecJSI_voidFunc}; + methodMap_["getBool"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_getBool}; + methodMap_["getNumber"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_getNumber}; + methodMap_["getString"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_getString}; + methodMap_["getArray"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_getArray}; + methodMap_["getObject"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_getObject}; + methodMap_["getValue"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleSpecJSI_getValue}; + methodMap_["getValueWithCallback"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithCallback}; + methodMap_["getValueWithPromise"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithPromise}; + methodMap_["getConstants"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleSpecJSI_getConstants}; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.h b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.h new file mode 100644 index 00000000000..e4fc54f788f --- /dev/null +++ b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.h @@ -0,0 +1,57 @@ +/** + * Copyright (c) Facebook, Inc. and its 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 + +#import + +#import +#import + +#import "NativeSampleTurboCxxModuleSpecJSI.h" + +namespace facebook { +namespace react { + +/** + * A sample implementation of the C++ spec. In practice, this class can just extend jsi::HostObject + * directly, but using the spec provides build-time type-safety. + */ +class SampleTurboCxxModule : public NativeSampleTurboCxxModuleSpecJSI { +public: + SampleTurboCxxModule(std::shared_ptr jsInvoker); + + void voidFunc(jsi::Runtime &rt) override; + bool getBool(jsi::Runtime &rt, bool arg) override; + double getNumber(jsi::Runtime &rt, double arg) override; + jsi::String getString(jsi::Runtime &rt, const jsi::String &arg) override; + jsi::Array getArray(jsi::Runtime &rt, const jsi::Array &arg) override; + jsi::Object getObject(jsi::Runtime &rt, const jsi::Object &arg) override; + jsi::Object getValue(jsi::Runtime &rt, double x, const jsi::String &y, const jsi::Object &z) override; + void getValueWithCallback(jsi::Runtime &rt, const jsi::Function &callback) override; + jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) override; + jsi::Object getConstants(jsi::Runtime &rt) override; +}; + +} // namespace react +} // namespace facebook + +/** + * Sample backward-compatible RCTCxxModule-based module. + * With jsi::HostObject, this class is no longer necessary, but the system supports it for + * backward compatibility. + */ +@interface RCTSampleTurboCxxModule_v1 : RCTCxxModule + +@end + +/** + * Second variant of a sample backward-compatible RCTCxxModule-based module. + */ +@interface RCTSampleTurboCxxModule_v2 : RCTCxxModule + +@end diff --git a/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.mm b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.mm new file mode 100644 index 00000000000..4fa19f1e8ba --- /dev/null +++ b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.mm @@ -0,0 +1,109 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTSampleTurboCxxModule.h" + +#import +#import + +#import "SampleTurboCxxModuleLegacyImpl.h" + +using namespace facebook; + +namespace facebook { +namespace react { + +SampleTurboCxxModule::SampleTurboCxxModule(std::shared_ptr jsInvoker) + : NativeSampleTurboCxxModuleSpecJSI(jsInvoker) {} + +void SampleTurboCxxModule::voidFunc(jsi::Runtime &rt) { + // Nothing to do +} + +bool SampleTurboCxxModule::getBool(jsi::Runtime &rt, bool arg) { + return arg; +} + +double SampleTurboCxxModule::getNumber(jsi::Runtime &rt, double arg) { + return arg; +} + +jsi::String SampleTurboCxxModule::getString(jsi::Runtime &rt, const jsi::String &arg) { + return jsi::String::createFromUtf8(rt, arg.utf8(rt)); +} + +jsi::Array SampleTurboCxxModule::getArray(jsi::Runtime &rt, const jsi::Array &arg) { + return deepCopyJSIArray(rt, arg); +} + +jsi::Object SampleTurboCxxModule::getObject(jsi::Runtime &rt, const jsi::Object &arg) { + return deepCopyJSIObject(rt, arg); +} + +jsi::Object SampleTurboCxxModule::getValue(jsi::Runtime &rt, double x, const jsi::String &y, const jsi::Object &z) { + // Note: return type isn't type-safe. + jsi::Object result(rt); + result.setProperty(rt, "x", jsi::Value(x)); + result.setProperty(rt, "y", jsi::String::createFromUtf8(rt, y.utf8(rt))); + result.setProperty(rt, "z", deepCopyJSIObject(rt, z)); + return result; +} + +void SampleTurboCxxModule::getValueWithCallback(jsi::Runtime &rt, const jsi::Function &callback) { + callback.call(rt, jsi::String::createFromUtf8(rt, "value from callback!")); +} + +jsi::Value SampleTurboCxxModule::getValueWithPromise(jsi::Runtime &rt, bool error) { + return createPromiseAsJSIValue(rt, [error](jsi::Runtime &rt2, std::shared_ptr promise) { + if (error) { + promise->reject("intentional promise rejection"); + } else { + promise->resolve(jsi::String::createFromUtf8(rt2, "result!")); + } + }); +} + +jsi::Object SampleTurboCxxModule::getConstants(jsi::Runtime &rt) { + // Note: return type isn't type-safe. + jsi::Object result(rt); + result.setProperty(rt, "const1", jsi::Value(true)); + result.setProperty(rt, "const2", jsi::Value(375)); + result.setProperty(rt, "const3", jsi::String::createFromUtf8(rt, "something")); + return result; +} + +} // namespace react +} // namespace facebook + + +// ObjC++ wrapper. +@implementation RCTSampleTurboCxxModule_v1 + +RCT_EXPORT_MODULE(); + +- (std::shared_ptr)getTurboModuleWithJsInvoker:(std::shared_ptr)jsInvoker +{ + return std::make_shared(jsInvoker); +} + +- (std::unique_ptr)createModule +{ + return nullptr; +} + +@end + +@implementation RCTSampleTurboCxxModule_v2 + +RCT_EXPORT_MODULE(); + +- (std::unique_ptr)createModule +{ + return std::make_unique(); +} + +@end diff --git a/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboModule.h b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboModule.h new file mode 100644 index 00000000000..0a9ebe2b738 --- /dev/null +++ b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboModule.h @@ -0,0 +1,18 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import "RCTNativeSampleTurboModuleSpec.h" + +/** + * Sample iOS-specific impl of a TurboModule, conforming to the spec protocol. + * This class is also 100% compatible with the NativeModule system. + */ +@interface RCTSampleTurboModule : NSObject + +@end diff --git a/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboModule.mm b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboModule.mm new file mode 100644 index 00000000000..2e0768efa66 --- /dev/null +++ b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboModule.mm @@ -0,0 +1,111 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTSampleTurboModule.h" + +#import + +using namespace facebook::react; + +@implementation RCTSampleTurboModule + +// Backward-compatible export +RCT_EXPORT_MODULE() + +@synthesize bridge = _bridge; +@synthesize turboModuleLookupDelegate = _turboModuleLookupDelegate; + +// Backward-compatible queue configuration +- (dispatch_queue_t)methodQueue +{ + return dispatch_get_main_queue(); +} + +- (std::shared_ptr)getTurboModuleWithJsInvoker:(std::shared_ptr)jsInvoker +{ + return std::make_shared(self, jsInvoker); +} + +- (NSDictionary *)getConstants +{ + UIScreen *mainScreen = UIScreen.mainScreen; + CGSize screenSize = mainScreen.bounds.size; + + return @{ + @"const1": @YES, + @"const2": @(screenSize.width), + @"const3": @"something", + }; +} + +// TODO: Remove once fully migrated to TurboModule. +- (NSDictionary *)constantsToExport +{ + return [self getConstants]; +} + +RCT_EXPORT_METHOD(voidFunc) +{ + // Nothing to do +} + +RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSNumber *, getBool:(BOOL)arg) +{ + return @(arg); +} + +RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSNumber *, getNumber:(double)arg) +{ + return @(arg); +} + +RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getString:(NSString *)arg) +{ + return arg; +} + +RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSArray> *, getArray:(NSArray *)arg) +{ + return arg; +} + +RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSDictionary *, getObject:(NSDictionary *)arg) +{ + return arg; +} + +RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSDictionary *, getValue:(double)x y:(NSString *)y z:(NSDictionary *)z) +{ + return @{ + @"x": @(x), + @"y": y ?: [NSNull null], + @"z": z ?: [NSNull null], + }; +} + +RCT_EXPORT_METHOD(getValueWithCallback:(RCTResponseSenderBlock)callback) +{ + if (!callback) { + return; + } + callback(@[@"value from callback!"]); +} + +RCT_EXPORT_METHOD(getValueWithPromise:(BOOL)error resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +{ + if (!resolve || !reject) { + return; + } + + if (error) { + reject(@"code_1", @"intentional promise rejection", [NSError errorWithDomain:@"RCTSampleTurboModule" code:1 userInfo:nil]); + } else { + resolve(@"result!"); + } +} + +@end diff --git a/ReactCommon/turbomodule/samples/platform/ios/SampleTurboCxxModuleLegacyImpl.cpp b/ReactCommon/turbomodule/samples/platform/ios/SampleTurboCxxModuleLegacyImpl.cpp new file mode 100644 index 00000000000..bd903e64c03 --- /dev/null +++ b/ReactCommon/turbomodule/samples/platform/ios/SampleTurboCxxModuleLegacyImpl.cpp @@ -0,0 +1,140 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "SampleTurboCxxModuleLegacyImpl.h" + +#include + +using namespace facebook::xplat::module; + +namespace facebook { +namespace react { + +SampleTurboCxxModuleLegacyImpl::SampleTurboCxxModuleLegacyImpl() {} + +std::string SampleTurboCxxModuleLegacyImpl::getName() { + return "SampleTurboCxxModule_v2"; +} + +std::map SampleTurboCxxModuleLegacyImpl::getConstants() { + return { + {"const1", true}, + {"const2", 375}, + {"const3", "something"}, + }; +}; + +std::vector SampleTurboCxxModuleLegacyImpl::getMethods() { + return { + CxxModule::Method( + "voidFunc", + [this](folly::dynamic args) { + voidFunc(); + }), + CxxModule::Method( + "getBool", + [this](folly::dynamic args) { + return getBool(xplat::jsArgAsBool(args, 0)); + }, + CxxModule::SyncTag), + CxxModule::Method( + "getNumber", + [this](folly::dynamic args) { + return getNumber(xplat::jsArgAsDouble(args, 0)); + }, + CxxModule::SyncTag), + CxxModule::Method( + "getString", + [this](folly::dynamic args) { + return getString(xplat::jsArgAsString(args, 0)); + }, + CxxModule::SyncTag), + CxxModule::Method( + "getString", + [this](folly::dynamic args) { + return getString(xplat::jsArgAsString(args, 0)); + }, + CxxModule::SyncTag), + CxxModule::Method( + "getArray", + [this](folly::dynamic args) { + return getArray(xplat::jsArgAsArray(args, 0)); + }, + CxxModule::SyncTag), + CxxModule::Method( + "getObject", + [this](folly::dynamic args) { + return getObject(xplat::jsArgAsObject(args, 0)); + }, + CxxModule::SyncTag), + CxxModule::Method( + "getValue", + [this](folly::dynamic args) { + return getValue( + xplat::jsArgAsDouble(args, 0), + xplat::jsArgAsString(args, 1), + xplat::jsArgAsObject(args, 2)); + }, + CxxModule::SyncTag), + CxxModule::Method( + "getValueWithCallback", + [this](folly::dynamic args, CxxModule::Callback callback) { + getValueWithCallback(callback); + }), + CxxModule::Method( + "getValueWithPromise", + [this](folly::dynamic args, CxxModule::Callback resolve, CxxModule::Callback reject) { + getValueWithPromise(xplat::jsArgAsBool(args, 0), resolve, reject); + }), + }; +}; + +void SampleTurboCxxModuleLegacyImpl::voidFunc() { + // Do nothing. +} + +bool SampleTurboCxxModuleLegacyImpl::getBool(bool arg) { + return arg; +} + +double SampleTurboCxxModuleLegacyImpl::getNumber(double arg) { + return arg; +} + +std::string SampleTurboCxxModuleLegacyImpl::getString(const std::string &arg) { + return arg; +} + +folly::dynamic SampleTurboCxxModuleLegacyImpl::getArray(const folly::dynamic &arg) { + return arg; +} + +folly::dynamic SampleTurboCxxModuleLegacyImpl::getObject(const folly::dynamic &arg) { + return arg; +} + +folly::dynamic SampleTurboCxxModuleLegacyImpl::getValue(double x, const std::string &y, const folly::dynamic &z) { + return folly::dynamic::object + ("x", x) + ("y", y) + ("z", z); +} + +void SampleTurboCxxModuleLegacyImpl::getValueWithCallback(const CxxModule::Callback &callback) { + callback({"value from callback!"}); +} + +void SampleTurboCxxModuleLegacyImpl::getValueWithPromise(bool error, const CxxModule::Callback &resolve, const CxxModule::Callback &reject) { + if (!error) { + resolve({"result!"}); + } else { + reject({folly::dynamic::object("message", "intentional promise rejection")}); + } +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/turbomodule/samples/platform/ios/SampleTurboCxxModuleLegacyImpl.h b/ReactCommon/turbomodule/samples/platform/ios/SampleTurboCxxModuleLegacyImpl.h new file mode 100644 index 00000000000..537f4c3c494 --- /dev/null +++ b/ReactCommon/turbomodule/samples/platform/ios/SampleTurboCxxModuleLegacyImpl.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) Facebook, Inc. and its 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 + +#import + +namespace facebook { +namespace react { + +/** + * A sample CxxModule (legacy system) implementation. + */ +class SampleTurboCxxModuleLegacyImpl : public facebook::xplat::module::CxxModule { +public: + SampleTurboCxxModuleLegacyImpl(); + + std::string getName() override; + std::map getConstants() override; + std::vector getMethods() override; + + // API + void voidFunc(); + bool getBool(bool arg); + double getNumber(double arg); + std::string getString(const std::string &arg); + folly::dynamic getArray(const folly::dynamic &arg); + folly::dynamic getObject(const folly::dynamic &arg); + folly::dynamic getValue(double x, const std::string &y, const folly::dynamic &z); + void getValueWithCallback(const facebook::xplat::module::CxxModule::Callback &callback); + void getValueWithPromise(bool error, const facebook::xplat::module::CxxModule::Callback &resolve, const facebook::xplat::module::CxxModule::Callback &reject); +}; + +} // namespace react +} // namespace facebook