164f5c95fSŁukasz Kosmaty // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
264f5c95fSŁukasz Kosmaty 
364f5c95fSŁukasz Kosmaty #pragma once
464f5c95fSŁukasz Kosmaty 
565a981ddSŁukasz Kosmaty #include "types/CppType.h"
665a981ddSŁukasz Kosmaty #include "types/ExpectedType.h"
765a981ddSŁukasz Kosmaty #include "types/AnyType.h"
86f5b8a20SŁukasz Kosmaty 
964f5c95fSŁukasz Kosmaty #include <jsi/jsi.h>
1064f5c95fSŁukasz Kosmaty #include <fbjni/fbjni.h>
1164f5c95fSŁukasz Kosmaty #include <ReactCommon/TurboModuleUtils.h>
1264f5c95fSŁukasz Kosmaty #include <react/jni/ReadableNativeArray.h>
1364f5c95fSŁukasz Kosmaty #include <memory>
1465a981ddSŁukasz Kosmaty #include <vector>
1564f5c95fSŁukasz Kosmaty #include <folly/dynamic.h>
1664f5c95fSŁukasz Kosmaty #include <jsi/JSIDynamic.h>
1764f5c95fSŁukasz Kosmaty 
1864f5c95fSŁukasz Kosmaty namespace jni = facebook::jni;
1964f5c95fSŁukasz Kosmaty namespace jsi = facebook::jsi;
2064f5c95fSŁukasz Kosmaty namespace react = facebook::react;
2164f5c95fSŁukasz Kosmaty 
2264f5c95fSŁukasz Kosmaty namespace expo {
2364f5c95fSŁukasz Kosmaty class JSIInteropModuleRegistry;
2464f5c95fSŁukasz Kosmaty 
2564f5c95fSŁukasz Kosmaty /**
2664f5c95fSŁukasz Kosmaty  * A class that holds information about the exported function.
2764f5c95fSŁukasz Kosmaty  */
2864f5c95fSŁukasz Kosmaty class MethodMetadata {
2964f5c95fSŁukasz Kosmaty public:
3064f5c95fSŁukasz Kosmaty   /**
3164f5c95fSŁukasz Kosmaty    * Function name
3264f5c95fSŁukasz Kosmaty    */
3364f5c95fSŁukasz Kosmaty   std::string name;
3464f5c95fSŁukasz Kosmaty   /**
35cf4fff55SŁukasz Kosmaty    * Whether this function takes owner
36cf4fff55SŁukasz Kosmaty    */
37cf4fff55SŁukasz Kosmaty   bool takesOwner;
38cf4fff55SŁukasz Kosmaty   /**
3964f5c95fSŁukasz Kosmaty    * Number of arguments
4064f5c95fSŁukasz Kosmaty    */
4164f5c95fSŁukasz Kosmaty   int args;
42cf4fff55SŁukasz Kosmaty   /**
4364f5c95fSŁukasz Kosmaty    * Whether this function is async
4464f5c95fSŁukasz Kosmaty    */
4564f5c95fSŁukasz Kosmaty   bool isAsync;
4665a981ddSŁukasz Kosmaty   /**
4765a981ddSŁukasz Kosmaty    * Representation of expected argument types.
4865a981ddSŁukasz Kosmaty    */
4965a981ddSŁukasz Kosmaty   std::vector<std::unique_ptr<AnyType>> argTypes;
509ebf31e6SŁukasz Kosmaty 
5164f5c95fSŁukasz Kosmaty   MethodMetadata(
5264f5c95fSŁukasz Kosmaty     std::string name,
53cf4fff55SŁukasz Kosmaty     bool takesOwner,
5464f5c95fSŁukasz Kosmaty     int args,
5564f5c95fSŁukasz Kosmaty     bool isAsync,
5665a981ddSŁukasz Kosmaty     jni::local_ref<jni::JArrayClass<ExpectedType>> expectedArgTypes,
5765a981ddSŁukasz Kosmaty     jni::global_ref<jobject> &&jBodyReference
5865a981ddSŁukasz Kosmaty   );
5965a981ddSŁukasz Kosmaty 
6065a981ddSŁukasz Kosmaty   MethodMetadata(
6165a981ddSŁukasz Kosmaty     std::string name,
62cf4fff55SŁukasz Kosmaty     bool takesOwner,
6365a981ddSŁukasz Kosmaty     int args,
6465a981ddSŁukasz Kosmaty     bool isAsync,
6565a981ddSŁukasz Kosmaty     std::vector<std::unique_ptr<AnyType>> &&expectedArgTypes,
6664f5c95fSŁukasz Kosmaty     jni::global_ref<jobject> &&jBodyReference
6764f5c95fSŁukasz Kosmaty   );
6864f5c95fSŁukasz Kosmaty 
6964f5c95fSŁukasz Kosmaty   // We deleted the copy contractor to not deal with transforming the ownership of the `jBodyReference`.
7064f5c95fSŁukasz Kosmaty   MethodMetadata(const MethodMetadata &) = delete;
7164f5c95fSŁukasz Kosmaty 
7247a022e6SŁukasz Kosmaty   MethodMetadata(MethodMetadata &&other) = default;
7347a022e6SŁukasz Kosmaty 
7464f5c95fSŁukasz Kosmaty   /**
7564f5c95fSŁukasz Kosmaty    * Transforms metadata to a jsi::Function.
7664f5c95fSŁukasz Kosmaty    *
7764f5c95fSŁukasz Kosmaty    * @param runtime
7864f5c95fSŁukasz Kosmaty    * @param moduleRegistry
7964f5c95fSŁukasz Kosmaty    * @return shared ptr to the jsi::Function that wrapped the underlying Kotlin's function.
8064f5c95fSŁukasz Kosmaty    */
8164f5c95fSŁukasz Kosmaty   std::shared_ptr<jsi::Function> toJSFunction(
8264f5c95fSŁukasz Kosmaty     jsi::Runtime &runtime,
8364f5c95fSŁukasz Kosmaty     JSIInteropModuleRegistry *moduleRegistry
8464f5c95fSŁukasz Kosmaty   );
8564f5c95fSŁukasz Kosmaty 
8647a022e6SŁukasz Kosmaty   /**
8747a022e6SŁukasz Kosmaty    * Calls the underlying Kotlin function.
8847a022e6SŁukasz Kosmaty    */
8947a022e6SŁukasz Kosmaty   jsi::Value callSync(
9047a022e6SŁukasz Kosmaty     jsi::Runtime &rt,
9147a022e6SŁukasz Kosmaty     JSIInteropModuleRegistry *moduleRegistry,
92cf4fff55SŁukasz Kosmaty     const jsi::Value &thisValue,
9347a022e6SŁukasz Kosmaty     const jsi::Value *args,
9447a022e6SŁukasz Kosmaty     size_t count
9547a022e6SŁukasz Kosmaty   );
9647a022e6SŁukasz Kosmaty 
97*ecb7f347SŁukasz Kosmaty   jni::local_ref<jobject> callJNISync(
98*ecb7f347SŁukasz Kosmaty     JNIEnv *env,
99*ecb7f347SŁukasz Kosmaty     jsi::Runtime &rt,
100*ecb7f347SŁukasz Kosmaty     JSIInteropModuleRegistry *moduleRegistry,
101*ecb7f347SŁukasz Kosmaty     const jsi::Value &thisValue,
102*ecb7f347SŁukasz Kosmaty     const jsi::Value *args,
103*ecb7f347SŁukasz Kosmaty     size_t count
104*ecb7f347SŁukasz Kosmaty   );
105*ecb7f347SŁukasz Kosmaty 
10664f5c95fSŁukasz Kosmaty private:
10764f5c95fSŁukasz Kosmaty   /**
10864f5c95fSŁukasz Kosmaty    * Reference to one of two java objects - `JNIFunctionBody` or `JNIAsyncFunctionBody`.
10964f5c95fSŁukasz Kosmaty    *
11064f5c95fSŁukasz Kosmaty    * In case when `isAsync` is `true`, this variable will point to `JNIAsyncFunctionBody`.
11164f5c95fSŁukasz Kosmaty    * Otherwise to `JNIFunctionBody`
11264f5c95fSŁukasz Kosmaty    */
11364f5c95fSŁukasz Kosmaty   jni::global_ref<jobject> jBodyReference;
11464f5c95fSŁukasz Kosmaty 
11564f5c95fSŁukasz Kosmaty   /**
11664f5c95fSŁukasz Kosmaty    * To not create a jsi::Function always when we need it, we cached that value.
11764f5c95fSŁukasz Kosmaty    */
11864f5c95fSŁukasz Kosmaty   std::shared_ptr<jsi::Function> body = nullptr;
11964f5c95fSŁukasz Kosmaty 
1209ebf31e6SŁukasz Kosmaty   jsi::Function toSyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry);
12164f5c95fSŁukasz Kosmaty 
12264f5c95fSŁukasz Kosmaty   jsi::Function toAsyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry);
12364f5c95fSŁukasz Kosmaty 
12464f5c95fSŁukasz Kosmaty   jsi::Function createPromiseBody(
12564f5c95fSŁukasz Kosmaty     jsi::Runtime &runtime,
12664f5c95fSŁukasz Kosmaty     JSIInteropModuleRegistry *moduleRegistry,
1277ed3a4bfSŁukasz Kosmaty     jobjectArray globalArgs
1289ebf31e6SŁukasz Kosmaty   );
1299ebf31e6SŁukasz Kosmaty 
1307ed3a4bfSŁukasz Kosmaty   jobjectArray convertJSIArgsToJNI(
1319ebf31e6SŁukasz Kosmaty     JSIInteropModuleRegistry *moduleRegistry,
1329ebf31e6SŁukasz Kosmaty     JNIEnv *env,
1339ebf31e6SŁukasz Kosmaty     jsi::Runtime &rt,
134cf4fff55SŁukasz Kosmaty     const jsi::Value &thisValue,
1359ebf31e6SŁukasz Kosmaty     const jsi::Value *args,
1367ed3a4bfSŁukasz Kosmaty     size_t count
13764f5c95fSŁukasz Kosmaty   );
13864f5c95fSŁukasz Kosmaty };
13964f5c95fSŁukasz Kosmaty } // namespace expo
140