1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #pragma once
4 
5 #include "JSIObjectWrapper.h"
6 
7 #include <fbjni/fbjni.h>
8 #include <jsi/jsi.h>
9 
10 #include <type_traits>
11 
12 namespace jni = facebook::jni;
13 namespace jsi = facebook::jsi;
14 
15 namespace expo {
16 /**
17  * A base template of the jni to jsi types converter.
18  * To make this conversion as fast and easy as possible we used the type trait technic.
19  */
20 template<class T, typename = void>
21 struct jsi_type_converter {
22   static const bool isDefined = false;
23 };
24 
25 /**
26  * Conversion from jni::alias_ref<T::javaobject> to jsi::Value where T extends JSIValueWrapper, JSIObjectWrapper or JSIFunctionWrapper.
27  */
28 template<class T>
29 struct jsi_type_converter<
30   jni::alias_ref<T>,
31   std::enable_if_t<
32     // jni::ReprType<T>::HybridType>::value if T looks like `R::javaobject`, it will return R
33     std::is_base_of<JSIValueWrapper, typename jni::ReprType<T>::HybridType>::value ||
34     std::is_base_of<JSIObjectWrapper, typename jni::ReprType<T>::HybridType>::value ||
35     std::is_base_of<JSIValueWrapper, typename jni::ReprType<T>::HybridType>::value
36   >
37 > {
38   static const bool isDefined = true;
39 
40   inline static jsi::Value convert(
41     jsi::Runtime &runtime,
42     jni::alias_ref<T> &value) {
43     if (value == nullptr) {
44       return jsi::Value::undefined();
45     }
46     return jsi::Value(runtime, *value->cthis()->get());
47   }
48 };
49 
50 /**
51  * Conversion from primitive types from which jsi::Value can be constructed (like bool, double) to jsi::Value.
52  */
53 template<class T>
54 struct jsi_type_converter<
55   T,
56   std::enable_if_t<std::is_fundamental_v<T> && std::is_constructible_v<jsi::Value, T>>
57 > {
58   static const bool isDefined = true;
59 
60   inline static jsi::Value convert(jsi::Runtime &runtime, T value) {
61     return jsi::Value(value);
62   }
63 };
64 
65 /**
66  * Conversion from jni::alias_ref<jstring> to jsi::Value.
67  */
68 template<>
69 struct jsi_type_converter<jni::alias_ref<jstring>> {
70   static const bool isDefined = true;
71 
72   inline static jsi::Value convert(jsi::Runtime &runtime, jni::alias_ref<jstring> &value) {
73     if (value == nullptr) {
74       return jsi::Value::undefined();
75     }
76     return jsi::Value(jsi::String::createFromUtf8(runtime, value->toStdString()));
77   }
78 };
79 
80 /**
81  * Helper that checks if the type converter was defined for the given type.
82  */
83 template<class T>
84 inline constexpr bool is_jsi_type_converter_defined = jsi_type_converter<T>::isDefined;
85 } // namespace expo
86