1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo) 2 3 #pragma once 4 5 #include "types/CppType.h" 6 #include "types/ExpectedType.h" 7 #include "types/AnyType.h" 8 9 #include <jsi/jsi.h> 10 #include <fbjni/fbjni.h> 11 #include <ReactCommon/TurboModuleUtils.h> 12 #include <react/jni/ReadableNativeArray.h> 13 #include <memory> 14 #include <vector> 15 #include <folly/dynamic.h> 16 #include <jsi/JSIDynamic.h> 17 18 namespace jni = facebook::jni; 19 namespace jsi = facebook::jsi; 20 namespace react = facebook::react; 21 22 namespace expo { 23 class JSIInteropModuleRegistry; 24 25 /** 26 * A class that holds information about the exported function. 27 */ 28 class MethodMetadata { 29 public: 30 /** 31 * Function name 32 */ 33 std::string name; 34 /** 35 * Whether this function takes owner 36 */ 37 bool takesOwner; 38 /** 39 * Number of arguments 40 */ 41 int args; 42 /** 43 * Whether this function is async 44 */ 45 bool isAsync; 46 /** 47 * Representation of expected argument types. 48 */ 49 std::vector<std::unique_ptr<AnyType>> argTypes; 50 51 MethodMetadata( 52 std::string name, 53 bool takesOwner, 54 int args, 55 bool isAsync, 56 jni::local_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes, 57 jni::global_ref<jobject> &&jBodyReference 58 ); 59 60 MethodMetadata( 61 std::string name, 62 bool takesOwner, 63 int args, 64 bool isAsync, 65 std::vector<std::unique_ptr<AnyType>> &&expectedArgTypes, 66 jni::global_ref<jobject> &&jBodyReference 67 ); 68 69 // We deleted the copy contractor to not deal with transforming the ownership of the `jBodyReference`. 70 MethodMetadata(const MethodMetadata &) = delete; 71 72 MethodMetadata(MethodMetadata &&other) = default; 73 74 /** 75 * Transforms metadata to a jsi::Function. 76 * 77 * @param runtime 78 * @param moduleRegistry 79 * @return shared ptr to the jsi::Function that wrapped the underlying Kotlin's function. 80 */ 81 std::shared_ptr<jsi::Function> toJSFunction( 82 jsi::Runtime &runtime, 83 JSIInteropModuleRegistry *moduleRegistry 84 ); 85 86 /** 87 * Calls the underlying Kotlin function. 88 */ 89 jsi::Value callSync( 90 jsi::Runtime &rt, 91 JSIInteropModuleRegistry *moduleRegistry, 92 const jsi::Value &thisValue, 93 const jsi::Value *args, 94 size_t count 95 ); 96 97 jni::local_ref<jobject> callJNISync( 98 JNIEnv *env, 99 jsi::Runtime &rt, 100 JSIInteropModuleRegistry *moduleRegistry, 101 const jsi::Value &thisValue, 102 const jsi::Value *args, 103 size_t count 104 ); 105 106 private: 107 /** 108 * Reference to one of two java objects - `JNIFunctionBody` or `JNIAsyncFunctionBody`. 109 * 110 * In case when `isAsync` is `true`, this variable will point to `JNIAsyncFunctionBody`. 111 * Otherwise to `JNIFunctionBody` 112 */ 113 jni::global_ref<jobject> jBodyReference; 114 115 /** 116 * To not create a jsi::Function always when we need it, we cached that value. 117 */ 118 std::shared_ptr<jsi::Function> body = nullptr; 119 120 jsi::Function toSyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry); 121 122 jsi::Function toAsyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry); 123 124 jsi::Function createPromiseBody( 125 jsi::Runtime &runtime, 126 JSIInteropModuleRegistry *moduleRegistry, 127 jobjectArray globalArgs 128 ); 129 130 jobjectArray convertJSIArgsToJNI( 131 JSIInteropModuleRegistry *moduleRegistry, 132 JNIEnv *env, 133 jsi::Runtime &rt, 134 const jsi::Value &thisValue, 135 const jsi::Value *args, 136 size_t count 137 ); 138 }; 139 } // namespace expo 140