1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #include "JavaScriptValue.h"
4 
5 #include "JavaScriptRuntime.h"
6 #include "JavaScriptObject.h"
7 #include "JavaScriptTypedArray.h"
8 #include "TypedArray.h"
9 
10 namespace expo {
11 void JavaScriptValue::registerNatives() {
12   registerHybrid({
13                    makeNativeMethod("kind", JavaScriptValue::jniKind),
14                    makeNativeMethod("isNull", JavaScriptValue::isNull),
15                    makeNativeMethod("isUndefined", JavaScriptValue::isUndefined),
16                    makeNativeMethod("isBool", JavaScriptValue::isBool),
17                    makeNativeMethod("isNumber", JavaScriptValue::isNumber),
18                    makeNativeMethod("isString", JavaScriptValue::isString),
19                    makeNativeMethod("isSymbol", JavaScriptValue::isSymbol),
20                    makeNativeMethod("isFunction", JavaScriptValue::isFunction),
21                    makeNativeMethod("isArray", JavaScriptValue::isArray),
22                    makeNativeMethod("isTypedArray", JavaScriptValue::isTypedArray),
23                    makeNativeMethod("isObject", JavaScriptValue::isObject),
24                    makeNativeMethod("getBool", JavaScriptValue::getBool),
25                    makeNativeMethod("getDouble", JavaScriptValue::getDouble),
26                    makeNativeMethod("getString", JavaScriptValue::jniGetString),
27                    makeNativeMethod("getObject", JavaScriptValue::getObject),
28                    makeNativeMethod("getArray", JavaScriptValue::getArray),
29                    makeNativeMethod("getTypedArray", JavaScriptValue::getTypedArray),
30                  });
31 }
32 
33 JavaScriptValue::JavaScriptValue(
34   std::weak_ptr<JavaScriptRuntime> runtime,
35   std::shared_ptr<jsi::Value> jsValue
36 ) : runtimeHolder(std::move(runtime)), jsValue(std::move(jsValue)) {
37   runtimeHolder.ensureRuntimeIsValid();
38 }
39 
40 JavaScriptValue::JavaScriptValue(
41   WeakRuntimeHolder runtime,
42   std::shared_ptr<jsi::Value> jsValue
43 ) : runtimeHolder(std::move(runtime)), jsValue(std::move(jsValue)) {
44   runtimeHolder.ensureRuntimeIsValid();
45 }
46 
47 std::shared_ptr<jsi::Value> JavaScriptValue::get() {
48   return jsValue;
49 }
50 
51 std::string JavaScriptValue::kind() {
52   if (isNull()) {
53     return "null";
54   }
55   if (isUndefined()) {
56     return "undefined";
57   }
58   if (isBool()) {
59     return "boolean";
60   }
61   if (isNumber()) {
62     return "number";
63   }
64   if (isString()) {
65     return "string";
66   }
67   if (isSymbol()) {
68     return "symbol";
69   }
70   if (isFunction()) {
71     return "function";
72   }
73   if (isArray()) {
74     return "array";
75   }
76   if (isObject()) {
77     return "object";
78   }
79 
80   // TODO(@lukmccall): maybe throw exception?
81   return "unknown";
82 }
83 
84 bool JavaScriptValue::isNull() {
85   return jsValue->isNull();
86 }
87 
88 bool JavaScriptValue::isUndefined() {
89   return jsValue->isUndefined();
90 }
91 
92 bool JavaScriptValue::isBool() {
93   return jsValue->isBool();
94 }
95 
96 bool JavaScriptValue::isNumber() {
97   return jsValue->isNumber();
98 }
99 
100 bool JavaScriptValue::isString() {
101   return jsValue->isString();
102 }
103 
104 bool JavaScriptValue::isSymbol() {
105   return jsValue->isSymbol();
106 }
107 
108 bool JavaScriptValue::isFunction() {
109   if (jsValue->isObject()) {
110     auto &jsRuntime = runtimeHolder.getJSRuntime();
111     return jsValue->asObject(jsRuntime).isFunction(jsRuntime);
112   }
113 
114   return false;
115 }
116 
117 bool JavaScriptValue::isArray() {
118   if (jsValue->isObject()) {
119     auto &jsRuntime = runtimeHolder.getJSRuntime();
120     return jsValue->asObject(jsRuntime).isArray(jsRuntime);
121   }
122 
123   return false;
124 }
125 
126 bool JavaScriptValue::isObject() {
127   return jsValue->isObject();
128 }
129 
130 bool JavaScriptValue::isTypedArray() {
131   if (jsValue->isObject()) {
132     jsi::Runtime &jsRuntime = runtimeHolder.getJSRuntime();
133     return expo::isTypedArray(jsRuntime, jsValue->getObject(jsRuntime));
134   }
135   return false;
136 }
137 
138 bool JavaScriptValue::getBool() {
139   return jsValue->getBool();
140 }
141 
142 double JavaScriptValue::getDouble() {
143   return jsValue->getNumber();
144 }
145 
146 std::string JavaScriptValue::getString() {
147   auto &jsRuntime = runtimeHolder.getJSRuntime();
148   return jsValue->getString(jsRuntime).utf8(jsRuntime);
149 }
150 
151 jni::local_ref<JavaScriptObject::javaobject> JavaScriptValue::getObject() {
152   auto &jsRuntime = runtimeHolder.getJSRuntime();
153   auto jsObject = std::make_shared<jsi::Object>(jsValue->getObject(jsRuntime));
154   return JavaScriptObject::newObjectCxxArgs(runtimeHolder, jsObject);
155 }
156 
157 jni::local_ref<jni::JArrayClass<JavaScriptValue::javaobject>> JavaScriptValue::getArray() {
158   auto &jsRuntime = runtimeHolder.getJSRuntime();
159 
160   auto jsArray = jsValue
161     ->getObject(jsRuntime)
162     .asArray(jsRuntime);
163   size_t size = jsArray.size(jsRuntime);
164 
165   auto result = jni::JArrayClass<JavaScriptValue::javaobject>::newArray(size);
166   for (size_t i = 0; i < size; i++) {
167     auto element = JavaScriptValue::newObjectCxxArgs(
168       runtimeHolder,
169       std::make_shared<jsi::Value>(jsArray.getValueAtIndex(jsRuntime, i))
170     );
171 
172     result->setElement(i, element.release());
173   }
174   return result;
175 }
176 
177 jni::local_ref<jstring> JavaScriptValue::jniKind() {
178   auto result = kind();
179   return jni::make_jstring(result);
180 }
181 jni::local_ref<jstring> JavaScriptValue::jniGetString() {
182   auto result = getString();
183   return jni::make_jstring(result);
184 }
185 
186 jni::local_ref<JavaScriptTypedArray::javaobject> JavaScriptValue::getTypedArray() {
187   auto &jsRuntime = runtimeHolder.getJSRuntime();
188   auto jsObject = std::make_shared<jsi::Object>(jsValue->getObject(jsRuntime));
189   return JavaScriptTypedArray::newObjectCxxArgs(runtimeHolder, jsObject);
190 }
191 } // namespace expo
192