1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #pragma once
4 
5 #include <jsi/jsi.h>
6 #include <fbjni/fbjni.h>
7 #include <ReactCommon/TurboModuleUtils.h>
8 #include <react/jni/ReadableNativeArray.h>
9 #include <memory>
10 #include <folly/dynamic.h>
11 #include <jsi/JSIDynamic.h>
12 
13 namespace jni = facebook::jni;
14 namespace jsi = facebook::jsi;
15 namespace react = facebook::react;
16 
17 namespace expo {
18 class JSIInteropModuleRegistry;
19 
20 /**
21  * A class that holds information about the exported function.
22  */
23 class MethodMetadata {
24 public:
25   /**
26    * Function name
27    */
28   std::string name;
29   /**
30    * Number of arguments
31    */
32   int args;
33   /*
34    * Whether this function is async
35    */
36   bool isAsync;
37 
38   MethodMetadata(
39     std::string name,
40     int args,
41     bool isAsync,
42     jni::global_ref<jobject> &&jBodyReference
43   );
44 
45   // We deleted the copy contractor to not deal with transforming the ownership of the `jBodyReference`.
46   MethodMetadata(const MethodMetadata &) = delete;
47 
48   /**
49    * MethodMetadata owns the only reference to the Kotlin function.
50    * We have to clean that, cause it's a `global_ref`.
51    */
52   ~MethodMetadata() {
53     jBodyReference.release();
54   }
55 
56   /**
57    * Transforms metadata to a jsi::Function.
58    *
59    * @param runtime
60    * @param moduleRegistry
61    * @return shared ptr to the jsi::Function that wrapped the underlying Kotlin's function.
62    */
63   std::shared_ptr<jsi::Function> toJSFunction(
64     jsi::Runtime &runtime,
65     JSIInteropModuleRegistry *moduleRegistry
66   );
67 
68 private:
69   /**
70    * Reference to one of two java objects - `JNIFunctionBody` or `JNIAsyncFunctionBody`.
71    *
72    * In case when `isAsync` is `true`, this variable will point to `JNIAsyncFunctionBody`.
73    * Otherwise to `JNIFunctionBody`
74    */
75   jni::global_ref<jobject> jBodyReference;
76 
77   /**
78    * To not create a jsi::Function always when we need it, we cached that value.
79    */
80   std::shared_ptr<jsi::Function> body = nullptr;
81 
82   jsi::Function toSyncFunction(jsi::Runtime &runtime);
83 
84   jsi::Function toAsyncFunction(jsi::Runtime &runtime, JSIInteropModuleRegistry *moduleRegistry);
85 
86   jsi::Function createPromiseBody(
87     jsi::Runtime &runtime,
88     JSIInteropModuleRegistry *moduleRegistry,
89     folly::dynamic &&args
90   );
91 };
92 } // namespace expo
93