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 "JavaScriptFunction.h"
9 #include "TypedArray.h"
10 #include "Exceptions.h"
11 #include "JSIInteropModuleRegistry.h"
12
13 namespace expo {
registerNatives()14 void JavaScriptValue::registerNatives() {
15 registerHybrid({
16 makeNativeMethod("kind", JavaScriptValue::jniKind),
17 makeNativeMethod("isNull", JavaScriptValue::isNull),
18 makeNativeMethod("isUndefined", JavaScriptValue::isUndefined),
19 makeNativeMethod("isBool", JavaScriptValue::isBool),
20 makeNativeMethod("isNumber", JavaScriptValue::isNumber),
21 makeNativeMethod("isString", JavaScriptValue::isString),
22 makeNativeMethod("isSymbol", JavaScriptValue::isSymbol),
23 makeNativeMethod("isFunction", JavaScriptValue::isFunction),
24 makeNativeMethod("isArray", JavaScriptValue::isArray),
25 makeNativeMethod("isTypedArray", JavaScriptValue::isTypedArray),
26 makeNativeMethod("isObject", JavaScriptValue::isObject),
27 makeNativeMethod("getBool", JavaScriptValue::getBool),
28 makeNativeMethod("getDouble", JavaScriptValue::getDouble),
29 makeNativeMethod("getString", JavaScriptValue::jniGetString),
30 makeNativeMethod("getObject", JavaScriptValue::getObject),
31 makeNativeMethod("getArray", JavaScriptValue::getArray),
32 makeNativeMethod("getTypedArray", JavaScriptValue::getTypedArray),
33 makeNativeMethod("jniGetFunction", JavaScriptValue::jniGetFunction),
34 });
35 }
36
JavaScriptValue(std::weak_ptr<JavaScriptRuntime> runtime,std::shared_ptr<jsi::Value> jsValue)37 JavaScriptValue::JavaScriptValue(
38 std::weak_ptr<JavaScriptRuntime> runtime,
39 std::shared_ptr<jsi::Value> jsValue
40 ) : runtimeHolder(std::move(runtime)), jsValue(std::move(jsValue)) {
41 runtimeHolder.ensureRuntimeIsValid();
42 }
43
JavaScriptValue(WeakRuntimeHolder runtime,std::shared_ptr<jsi::Value> jsValue)44 JavaScriptValue::JavaScriptValue(
45 WeakRuntimeHolder runtime,
46 std::shared_ptr<jsi::Value> jsValue
47 ) : runtimeHolder(std::move(runtime)), jsValue(std::move(jsValue)) {
48 runtimeHolder.ensureRuntimeIsValid();
49 }
50
get()51 std::shared_ptr<jsi::Value> JavaScriptValue::get() {
52 return jsValue;
53 }
54
kind()55 std::string JavaScriptValue::kind() {
56 if (isNull()) {
57 return "null";
58 }
59 if (isUndefined()) {
60 return "undefined";
61 }
62 if (isBool()) {
63 return "boolean";
64 }
65 if (isNumber()) {
66 return "number";
67 }
68 if (isString()) {
69 return "string";
70 }
71 if (isSymbol()) {
72 return "symbol";
73 }
74 if (isFunction()) {
75 return "function";
76 }
77 if (isArray()) {
78 return "array";
79 }
80 if (isObject()) {
81 return "object";
82 }
83
84 throwNewJavaException(
85 UnexpectedException::create("Unknown type").get()
86 );
87 }
88
isNull()89 bool JavaScriptValue::isNull() {
90 return jsValue->isNull();
91 }
92
isUndefined()93 bool JavaScriptValue::isUndefined() {
94 return jsValue->isUndefined();
95 }
96
isBool()97 bool JavaScriptValue::isBool() {
98 return jsValue->isBool();
99 }
100
isNumber()101 bool JavaScriptValue::isNumber() {
102 return jsValue->isNumber();
103 }
104
isString()105 bool JavaScriptValue::isString() {
106 return jsValue->isString();
107 }
108
isSymbol()109 bool JavaScriptValue::isSymbol() {
110 return jsValue->isSymbol();
111 }
112
isFunction()113 bool JavaScriptValue::isFunction() {
114 if (jsValue->isObject()) {
115 auto &jsRuntime = runtimeHolder.getJSRuntime();
116 return jsValue->asObject(jsRuntime).isFunction(jsRuntime);
117 }
118
119 return false;
120 }
121
isArray()122 bool JavaScriptValue::isArray() {
123 if (jsValue->isObject()) {
124 auto &jsRuntime = runtimeHolder.getJSRuntime();
125 return jsValue->asObject(jsRuntime).isArray(jsRuntime);
126 }
127
128 return false;
129 }
130
isObject()131 bool JavaScriptValue::isObject() {
132 return jsValue->isObject();
133 }
134
isTypedArray()135 bool JavaScriptValue::isTypedArray() {
136 if (jsValue->isObject()) {
137 jsi::Runtime &jsRuntime = runtimeHolder.getJSRuntime();
138 return expo::isTypedArray(jsRuntime, jsValue->getObject(jsRuntime));
139 }
140 return false;
141 }
142
getBool()143 bool JavaScriptValue::getBool() {
144 return jsValue->getBool();
145 }
146
getDouble()147 double JavaScriptValue::getDouble() {
148 return jsValue->getNumber();
149 }
150
getString()151 std::string JavaScriptValue::getString() {
152 auto &jsRuntime = runtimeHolder.getJSRuntime();
153 return jsValue->getString(jsRuntime).utf8(jsRuntime);
154 }
155
getObject()156 jni::local_ref<JavaScriptObject::javaobject> JavaScriptValue::getObject() {
157 auto &jsRuntime = runtimeHolder.getJSRuntime();
158 auto jsObject = std::make_shared<jsi::Object>(jsValue->getObject(jsRuntime));
159 return JavaScriptObject::newInstance(
160 runtimeHolder.getModuleRegistry(),
161 runtimeHolder,
162 jsObject
163 );
164 }
165
jniGetFunction()166 jni::local_ref<JavaScriptFunction::javaobject> JavaScriptValue::jniGetFunction() {
167 auto &jsRuntime = runtimeHolder.getJSRuntime();
168 auto jsFunction = std::make_shared<jsi::Function>(
169 jsValue->getObject(jsRuntime).asFunction(jsRuntime));
170 return JavaScriptFunction::newInstance(
171 runtimeHolder.getModuleRegistry(),
172 runtimeHolder,
173 jsFunction
174 );
175 }
176
getArray()177 jni::local_ref<jni::JArrayClass<JavaScriptValue::javaobject>> JavaScriptValue::getArray() {
178 auto &jsRuntime = runtimeHolder.getJSRuntime();
179 auto moduleRegistry = runtimeHolder.getModuleRegistry();
180
181 auto jsArray = jsValue
182 ->getObject(jsRuntime)
183 .asArray(jsRuntime);
184 size_t size = jsArray.size(jsRuntime);
185
186 auto result = jni::JArrayClass<JavaScriptValue::javaobject>::newArray(size);
187 for (size_t i = 0; i < size; i++) {
188 auto element = JavaScriptValue::newInstance(
189 moduleRegistry,
190 runtimeHolder,
191 std::make_shared<jsi::Value>(jsArray.getValueAtIndex(jsRuntime, i))
192 );
193
194 result->setElement(i, element.release());
195 }
196 return result;
197 }
198
jniKind()199 jni::local_ref<jstring> JavaScriptValue::jniKind() {
200 auto result = kind();
201 return jni::make_jstring(result);
202 }
203
jniGetString()204 jni::local_ref<jstring> JavaScriptValue::jniGetString() {
205 auto result = getString();
206 return jni::make_jstring(result);
207 }
208
getTypedArray()209 jni::local_ref<JavaScriptTypedArray::javaobject> JavaScriptValue::getTypedArray() {
210 auto &jsRuntime = runtimeHolder.getJSRuntime();
211 auto jsObject = std::make_shared<jsi::Object>(jsValue->getObject(jsRuntime));
212 return JavaScriptTypedArray::newInstance(
213 runtimeHolder.getModuleRegistry(),
214 runtimeHolder,
215 jsObject
216 );
217 }
218
newInstance(JSIInteropModuleRegistry * jsiInteropModuleRegistry,std::weak_ptr<JavaScriptRuntime> runtime,std::shared_ptr<jsi::Value> jsValue)219 jni::local_ref<JavaScriptValue::javaobject> JavaScriptValue::newInstance(
220 JSIInteropModuleRegistry *jsiInteropModuleRegistry,
221 std::weak_ptr<JavaScriptRuntime> runtime,
222 std::shared_ptr<jsi::Value> jsValue
223 ) {
224 auto value = JavaScriptValue::newObjectCxxArgs(
225 std::move(runtime),
226 std::move(jsValue)
227 );
228 jsiInteropModuleRegistry->jniDeallocator->addReference(value);
229 return value;
230 }
231 } // namespace expo
232