expo-modules-jsi 58.0.4 → 58.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -5
- package/apple/Benchmarks/HostObjectBenchmarks.swift +57 -0
- package/apple/Sources/ExpoModulesJSI/Coding/JavaScriptCodable+Primitives.swift +4 -6
- package/apple/Sources/ExpoModulesJSI/Protocols/JSIRepresentable.swift +2 -2
- package/apple/Sources/ExpoModulesJSI/Protocols/JavaScriptRepresentable.swift +2 -3
- package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntime.swift +24 -17
- package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntimeHandle.swift +67 -0
- package/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptValuesBuffer.swift +3 -2
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptArray.swift +53 -35
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptFunction.swift +2 -2
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptObject.swift +79 -59
- package/apple/Sources/ExpoModulesJSI/Runtime/Values/JavaScriptValue.swift +63 -46
- package/apple/Sources/ExpoModulesJSI/Utilities/String+JSI.swift +10 -0
- package/apple/Sources/ExpoModulesJSI-Cxx/include/HostObject.h +2 -2
- package/apple/Sources/ExpoModulesJSI-Cxx/include/HostObjectCallbacks.h +17 -8
- package/apple/Sources/ExpoModulesJSI-Cxx/include/JSIUtils.h +20 -0
- package/apple/Tests/JavaScriptRuntimeTests.swift +40 -0
- package/apple/Tests/JavaScriptValueTests.swift +18 -0
- package/apple/Tests/JavaScriptValuesBufferTests.swift +14 -0
- package/package.json +1 -2
- package/apple/.generated/module.modulemap +0 -6
- package/apple/Products/ExpoModulesJSI.xcframework/Info.plist +0 -107
- package/apple/Products/ExpoModulesJSI.xcframework/ios-arm64/.build-hash +0 -0
- package/apple/Products/ExpoModulesJSI.xcframework/ios-arm64/ExpoModulesJSI.framework/ExpoModulesJSI +0 -0
- package/apple/Products/ExpoModulesJSI.xcframework/ios-arm64_x86_64-maccatalyst/.build-hash +0 -0
- package/apple/Products/ExpoModulesJSI.xcframework/ios-arm64_x86_64-maccatalyst/ExpoModulesJSI.framework/ExpoModulesJSI +0 -0
- package/apple/Products/ExpoModulesJSI.xcframework/ios-arm64_x86_64-simulator/.build-hash +0 -0
- package/apple/Products/ExpoModulesJSI.xcframework/ios-arm64_x86_64-simulator/ExpoModulesJSI.framework/ExpoModulesJSI +0 -0
- package/apple/Products/ExpoModulesJSI.xcframework/macos-arm64_x86_64/.build-hash +0 -0
- package/apple/Products/ExpoModulesJSI.xcframework/macos-arm64_x86_64/ExpoModulesJSI.framework/ExpoModulesJSI +0 -0
- package/apple/Products/ExpoModulesJSI.xcframework/tvos-arm64/.build-hash +0 -0
- package/apple/Products/ExpoModulesJSI.xcframework/tvos-arm64/ExpoModulesJSI.framework/ExpoModulesJSI +0 -0
- package/apple/Products/ExpoModulesJSI.xcframework/tvos-arm64_x86_64-simulator/.build-hash +0 -0
- package/apple/Products/ExpoModulesJSI.xcframework/tvos-arm64_x86_64-simulator/ExpoModulesJSI.framework/ExpoModulesJSI +0 -0
|
@@ -6,32 +6,53 @@ internal import jsi
|
|
|
6
6
|
/// A Swift representation of a JavaScript object. Provides access to JavaScript object properties and methods,
|
|
7
7
|
/// supporting property access, modification, enumeration, prototype manipulation, and function calling.
|
|
8
8
|
public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
9
|
-
|
|
9
|
+
/// Handle to the runtime the object belongs to.
|
|
10
|
+
internal let runtimeHandle: JavaScriptRuntimeHandle
|
|
10
11
|
internal var pointee: facebook.jsi.Object
|
|
11
12
|
|
|
13
|
+
/// The runtime the object belongs to, or `nil` if it has been deallocated. Prefer ``jsiRuntime`` on
|
|
14
|
+
/// hot paths: it costs no reference counting.
|
|
15
|
+
internal var runtime: JavaScriptRuntime? {
|
|
16
|
+
return runtimeHandle.runtime
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/// The engine runtime the object belongs to, or `nil` if the runtime has been deallocated.
|
|
20
|
+
internal var jsiRuntime: facebook.jsi.IRuntime? {
|
|
21
|
+
return runtimeHandle.pointee
|
|
22
|
+
}
|
|
23
|
+
|
|
12
24
|
/// Creates a new object in the given runtime.
|
|
13
|
-
public init(_ runtime: JavaScriptRuntime) {
|
|
25
|
+
public init(_ runtime: borrowing JavaScriptRuntime) {
|
|
14
26
|
self.init(runtime, facebook.jsi.Object(runtime.pointee))
|
|
15
27
|
}
|
|
16
28
|
|
|
17
29
|
/// Creates a new object from the dictionary whose values are representable in JS.
|
|
18
|
-
public init<DictValue: JavaScriptRepresentable>(
|
|
19
|
-
|
|
30
|
+
public init<DictValue: JavaScriptRepresentable>(
|
|
31
|
+
_ runtime: borrowing JavaScriptRuntime,
|
|
32
|
+
_ dictionary: [String: DictValue]
|
|
33
|
+
) {
|
|
34
|
+
self.runtimeHandle = runtime.handle
|
|
20
35
|
self.pointee = dictionary.toJavaScriptValue(in: runtime).getObject().pointee
|
|
21
36
|
}
|
|
22
37
|
|
|
23
38
|
/// Creates a new object from existing JSI object.
|
|
24
|
-
internal init(_ runtime: JavaScriptRuntime, _ object: consuming facebook.jsi.Object) {
|
|
25
|
-
self.
|
|
39
|
+
internal init(_ runtime: borrowing JavaScriptRuntime, _ object: consuming facebook.jsi.Object) {
|
|
40
|
+
self.runtimeHandle = runtime.handle
|
|
41
|
+
self.pointee = object
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Creates a new object from existing JSI object, which belongs to the runtime behind `runtimeHandle`.
|
|
45
|
+
internal init(_ runtimeHandle: JavaScriptRuntimeHandle, _ object: consuming facebook.jsi.Object) {
|
|
46
|
+
self.runtimeHandle = runtimeHandle
|
|
26
47
|
self.pointee = object
|
|
27
48
|
}
|
|
28
49
|
|
|
29
50
|
/// Result of `object instanceof constructor`, which tests if the prototype property of a constructor appears anywhere in the prototype chain of an object.
|
|
30
51
|
public func instanceOf(_ constructor: borrowing JavaScriptFunction) -> Bool {
|
|
31
|
-
guard let
|
|
52
|
+
guard let jsiRuntime else {
|
|
32
53
|
FatalError.runtimeLost()
|
|
33
54
|
}
|
|
34
|
-
return pointee.instanceOf(
|
|
55
|
+
return pointee.instanceOf(jsiRuntime, constructor.pointee)
|
|
35
56
|
}
|
|
36
57
|
|
|
37
58
|
/// Result of `object instanceof constructor`, which tests if the prototype property of a constructor appears anywhere in the prototype chain of an object.
|
|
@@ -41,34 +62,34 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
41
62
|
|
|
42
63
|
/// Equivalent to `Array.isArray()` in JS. If it returns `true`, then `getArray()` will succeed.
|
|
43
64
|
public func isArray() -> Bool {
|
|
44
|
-
guard let
|
|
65
|
+
guard let jsiRuntime else {
|
|
45
66
|
FatalError.runtimeLost()
|
|
46
67
|
}
|
|
47
|
-
return pointee.isArray(
|
|
68
|
+
return pointee.isArray(jsiRuntime)
|
|
48
69
|
}
|
|
49
70
|
|
|
50
71
|
/// Returns `true` if the object is callable. If so, then `getFunction()` will succeed.
|
|
51
72
|
public func isFunction() -> Bool {
|
|
52
|
-
guard let
|
|
73
|
+
guard let jsiRuntime else {
|
|
53
74
|
FatalError.runtimeLost()
|
|
54
75
|
}
|
|
55
|
-
return pointee.isFunction(
|
|
76
|
+
return pointee.isFunction(jsiRuntime)
|
|
56
77
|
}
|
|
57
78
|
|
|
58
79
|
/// Returns `true` if the object is backed by a `jsi::HostObject`, including host objects
|
|
59
80
|
/// created via `JavaScriptRuntime.createHostObject` and ones produced by other native code.
|
|
60
81
|
public func isHostObject() -> Bool {
|
|
61
|
-
guard let
|
|
82
|
+
guard let jsiRuntime else {
|
|
62
83
|
FatalError.runtimeLost()
|
|
63
84
|
}
|
|
64
|
-
return expo.isHostObject(
|
|
85
|
+
return expo.isHostObject(jsiRuntime, pointee)
|
|
65
86
|
}
|
|
66
87
|
|
|
67
88
|
public func isArrayBuffer() -> Bool {
|
|
68
|
-
guard let
|
|
89
|
+
guard let jsiRuntime else {
|
|
69
90
|
FatalError.runtimeLost()
|
|
70
91
|
}
|
|
71
|
-
return pointee.isArrayBuffer(
|
|
92
|
+
return pointee.isArrayBuffer(jsiRuntime)
|
|
72
93
|
}
|
|
73
94
|
|
|
74
95
|
/// Returns the object as an array buffer, or asserts if not an array buffer.
|
|
@@ -82,11 +103,11 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
82
103
|
|
|
83
104
|
/// Returns the object as an array, or asserts if not an array.
|
|
84
105
|
public func getArray() -> JavaScriptArray {
|
|
85
|
-
guard let
|
|
106
|
+
guard let jsiRuntime else {
|
|
86
107
|
FatalError.runtimeLost()
|
|
87
108
|
}
|
|
88
109
|
assert(isArray(), "Object is not an array")
|
|
89
|
-
return JavaScriptArray(
|
|
110
|
+
return JavaScriptArray(runtimeHandle, pointee.getArray(jsiRuntime))
|
|
90
111
|
}
|
|
91
112
|
|
|
92
113
|
/// Returns the object as a function, or asserts if not a function.
|
|
@@ -102,28 +123,28 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
102
123
|
|
|
103
124
|
/// Checks whether the object has a property with the given name.
|
|
104
125
|
public func hasProperty(_ name: String) -> Bool {
|
|
105
|
-
guard let
|
|
126
|
+
guard let jsiRuntime else {
|
|
106
127
|
FatalError.runtimeLost()
|
|
107
128
|
}
|
|
108
|
-
return pointee.hasProperty(
|
|
129
|
+
return pointee.hasProperty(jsiRuntime, name.toJSIPropNameID(in: jsiRuntime))
|
|
109
130
|
}
|
|
110
131
|
|
|
111
132
|
/// Returns the property of the object with the given name,
|
|
112
133
|
/// or `undefined` value if the name is not a property of the object.
|
|
113
134
|
public func getProperty(_ name: String) -> JavaScriptValue {
|
|
114
|
-
guard let
|
|
135
|
+
guard let jsiRuntime else {
|
|
115
136
|
FatalError.runtimeLost()
|
|
116
137
|
}
|
|
117
|
-
return JavaScriptValue(
|
|
138
|
+
return JavaScriptValue(runtimeHandle, pointee.getProperty(jsiRuntime, name.toJSIPropNameID(in: jsiRuntime)))
|
|
118
139
|
}
|
|
119
140
|
|
|
120
141
|
/// Returns the property of the object with the given prop name id,
|
|
121
142
|
/// or `undefined` value if the name is not a property of the object.
|
|
122
143
|
public func getProperty(_ propName: JavaScriptPropNameID) -> JavaScriptValue {
|
|
123
|
-
guard let
|
|
144
|
+
guard let jsiRuntime else {
|
|
124
145
|
FatalError.runtimeLost()
|
|
125
146
|
}
|
|
126
|
-
return JavaScriptValue(
|
|
147
|
+
return JavaScriptValue(runtimeHandle, pointee.getProperty(jsiRuntime, propName.pointee))
|
|
127
148
|
}
|
|
128
149
|
|
|
129
150
|
/// Accesses nested properties in a single subscript operation by traversing the object chain.
|
|
@@ -138,16 +159,15 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
138
159
|
/// - Note: Each intermediate value in the chain (except the last) must be an object.
|
|
139
160
|
/// If any intermediate value is not an object, the behavior is undefined and may crash.
|
|
140
161
|
public subscript(_ key: String, _ nestedKeys: String...) -> JavaScriptValue {
|
|
141
|
-
guard let
|
|
162
|
+
guard let jsiRuntime else {
|
|
142
163
|
FatalError.runtimeLost()
|
|
143
164
|
}
|
|
144
|
-
let jsiRuntime = runtime.pointee
|
|
145
165
|
var value = pointee.getProperty(jsiRuntime, key)
|
|
146
166
|
|
|
147
167
|
for key in nestedKeys {
|
|
148
168
|
value = value.getObject(jsiRuntime).getProperty(jsiRuntime, key)
|
|
149
169
|
}
|
|
150
|
-
return JavaScriptValue(
|
|
170
|
+
return JavaScriptValue(runtimeHandle, value)
|
|
151
171
|
}
|
|
152
172
|
|
|
153
173
|
/// Returns an array of the object's own enumerable property names.
|
|
@@ -156,7 +176,7 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
156
176
|
///
|
|
157
177
|
/// - Returns: An array of property names as strings
|
|
158
178
|
public func getPropertyNames() -> [String] {
|
|
159
|
-
guard let jsiRuntime
|
|
179
|
+
guard let jsiRuntime else {
|
|
160
180
|
FatalError.runtimeLost()
|
|
161
181
|
}
|
|
162
182
|
let propertyNames: facebook.jsi.Array = pointee.getPropertyNames(jsiRuntime)
|
|
@@ -209,32 +229,32 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
209
229
|
|
|
210
230
|
/// Returns a prototype of the object. Same as `Object.getPrototypeOf(object)` in JS.
|
|
211
231
|
public func getPrototype() -> JavaScriptValue {
|
|
212
|
-
guard let
|
|
232
|
+
guard let jsiRuntime else {
|
|
213
233
|
FatalError.runtimeLost()
|
|
214
234
|
}
|
|
215
|
-
return JavaScriptValue(
|
|
235
|
+
return JavaScriptValue(runtimeHandle, pointee.getPrototype(jsiRuntime))
|
|
216
236
|
}
|
|
217
237
|
|
|
218
238
|
/// Sets a prototype of the object. Same as `Object.setPrototypeOf(object, prototype)` in JS.
|
|
219
239
|
public func setPrototype(_ prototype: JavaScriptValue) {
|
|
220
|
-
guard let
|
|
240
|
+
guard let jsiRuntime else {
|
|
221
241
|
FatalError.runtimeLost()
|
|
222
242
|
}
|
|
223
|
-
pointee.setPrototype(
|
|
243
|
+
pointee.setPrototype(jsiRuntime, prototype.pointee)
|
|
224
244
|
}
|
|
225
245
|
|
|
226
246
|
// MARK: - Modifying object properties
|
|
227
247
|
|
|
228
248
|
public func setProperty(_ name: String, value: JavaScriptValue) {
|
|
229
|
-
guard let
|
|
249
|
+
guard let jsiRuntime else {
|
|
230
250
|
FatalError.runtimeLost()
|
|
231
251
|
}
|
|
232
252
|
// This specialization is to avoid copying the value; `asValue()` on `JavaScriptValue` needs to do a copy.
|
|
233
253
|
expo.setProperty(
|
|
234
|
-
|
|
254
|
+
jsiRuntime,
|
|
235
255
|
pointee,
|
|
236
|
-
name.toJSIPropNameID(in:
|
|
237
|
-
value.toJSIValue(in:
|
|
256
|
+
name.toJSIPropNameID(in: jsiRuntime),
|
|
257
|
+
value.toJSIValue(in: jsiRuntime)
|
|
238
258
|
)
|
|
239
259
|
}
|
|
240
260
|
|
|
@@ -247,22 +267,22 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
247
267
|
}
|
|
248
268
|
|
|
249
269
|
internal func setProperty<T: JavaScriptRepresentable>(_ name: String, value: consuming T) where T: JSIRepresentable {
|
|
250
|
-
guard let
|
|
270
|
+
guard let jsiRuntime else {
|
|
251
271
|
FatalError.runtimeLost()
|
|
252
272
|
}
|
|
253
|
-
let jsiValue = value.toJSIValue(in:
|
|
254
|
-
expo.setProperty(
|
|
273
|
+
let jsiValue = value.toJSIValue(in: jsiRuntime)
|
|
274
|
+
expo.setProperty(jsiRuntime, pointee, name.toJSIPropNameID(in: jsiRuntime), jsiValue)
|
|
255
275
|
}
|
|
256
276
|
|
|
257
277
|
public func setProperty(_ name: String, _ object: consuming JavaScriptObject) {
|
|
258
|
-
guard let
|
|
278
|
+
guard let jsiRuntime else {
|
|
259
279
|
FatalError.runtimeLost()
|
|
260
280
|
}
|
|
261
281
|
expo.setProperty(
|
|
262
|
-
|
|
282
|
+
jsiRuntime,
|
|
263
283
|
pointee,
|
|
264
|
-
name.toJSIPropNameID(in:
|
|
265
|
-
facebook.jsi.Value(
|
|
284
|
+
name.toJSIPropNameID(in: jsiRuntime),
|
|
285
|
+
facebook.jsi.Value(jsiRuntime, object.pointee)
|
|
266
286
|
)
|
|
267
287
|
}
|
|
268
288
|
|
|
@@ -314,10 +334,10 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
314
334
|
#if !os(macOS)
|
|
315
335
|
// TODO: remove when bumping to react-native-macos 0.86
|
|
316
336
|
public func deleteProperty(_ name: String) {
|
|
317
|
-
guard let
|
|
337
|
+
guard let jsiRuntime else {
|
|
318
338
|
FatalError.runtimeLost()
|
|
319
339
|
}
|
|
320
|
-
pointee.deleteProperty(
|
|
340
|
+
pointee.deleteProperty(jsiRuntime, name.toJSIPropNameID(in: jsiRuntime))
|
|
321
341
|
}
|
|
322
342
|
#endif
|
|
323
343
|
|
|
@@ -381,18 +401,18 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
381
401
|
// MARK: - Conversions
|
|
382
402
|
|
|
383
403
|
public func asValue() -> JavaScriptValue {
|
|
384
|
-
guard let
|
|
404
|
+
guard let jsiRuntime else {
|
|
385
405
|
FatalError.runtimeLost()
|
|
386
406
|
}
|
|
387
|
-
return JavaScriptValue(
|
|
407
|
+
return JavaScriptValue(runtimeHandle, facebook.jsi.Value(jsiRuntime, pointee))
|
|
388
408
|
}
|
|
389
409
|
|
|
390
410
|
/// Returns the object as a `facebook.jsi.Value` instance.
|
|
391
411
|
internal func asJSIValue() -> facebook.jsi.Value {
|
|
392
|
-
guard let
|
|
412
|
+
guard let jsiRuntime else {
|
|
393
413
|
FatalError.runtimeLost()
|
|
394
414
|
}
|
|
395
|
-
return facebook.jsi.Value(
|
|
415
|
+
return facebook.jsi.Value(jsiRuntime, pointee)
|
|
396
416
|
}
|
|
397
417
|
|
|
398
418
|
/// Provides scoped access to a raw pointer to the underlying `facebook.jsi.Object`.
|
|
@@ -428,10 +448,10 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
428
448
|
/// wrapper: C++-produced states carry a null context and are unrecoverable from
|
|
429
449
|
/// the Swift side by design.
|
|
430
450
|
public func hasNativeState() -> Bool {
|
|
431
|
-
guard let
|
|
451
|
+
guard let jsiRuntime else {
|
|
432
452
|
FatalError.runtimeLost()
|
|
433
453
|
}
|
|
434
|
-
return expo.hasNativeState(
|
|
454
|
+
return expo.hasNativeState(jsiRuntime, pointee)
|
|
435
455
|
}
|
|
436
456
|
|
|
437
457
|
/// Returns the Swift `JavaScriptNativeState` wrapper attached to this object via
|
|
@@ -439,10 +459,10 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
439
459
|
/// produced C++-side without a Swift back-pointer, or its concrete type doesn't
|
|
440
460
|
/// match `T`.
|
|
441
461
|
public func getNativeState<T: JavaScriptNativeState>(as: T.Type = JavaScriptNativeState.self) -> T? {
|
|
442
|
-
guard let
|
|
462
|
+
guard let jsiRuntime else {
|
|
443
463
|
FatalError.runtimeLost()
|
|
444
464
|
}
|
|
445
|
-
guard let cxxNativeState = expo.getExpoNativeState(
|
|
465
|
+
guard let cxxNativeState = expo.getExpoNativeState(jsiRuntime, pointee) else {
|
|
446
466
|
return nil
|
|
447
467
|
}
|
|
448
468
|
return T.from(cxx: cxxNativeState)
|
|
@@ -452,27 +472,27 @@ public struct JavaScriptObject: JavaScriptType, Sendable, ~Copyable {
|
|
|
452
472
|
/// Creates a new shared_ptr to the object managed by state, which will live until the value at this property becomes unreachable.
|
|
453
473
|
/// - TODO: throw a type error if this object is a proxy or host object.
|
|
454
474
|
public func setNativeState<T: JavaScriptNativeState>(_ nativeState: T) {
|
|
455
|
-
guard let
|
|
475
|
+
guard let jsiRuntime else {
|
|
456
476
|
FatalError.runtimeLost()
|
|
457
477
|
}
|
|
458
|
-
expo.setNativeState(
|
|
478
|
+
expo.setNativeState(jsiRuntime, self.pointee, nativeState.acquireShared())
|
|
459
479
|
}
|
|
460
480
|
|
|
461
481
|
/// Unsets the native state of this object.
|
|
462
482
|
public func unsetNativeState() {
|
|
463
|
-
guard let
|
|
483
|
+
guard let jsiRuntime else {
|
|
464
484
|
FatalError.runtimeLost()
|
|
465
485
|
}
|
|
466
|
-
expo.unsetNativeState(
|
|
486
|
+
expo.unsetNativeState(jsiRuntime, pointee)
|
|
467
487
|
}
|
|
468
488
|
|
|
469
489
|
// MARK: - Memory pressure
|
|
470
490
|
|
|
471
491
|
public func setExternalMemoryPressure(_ size: Int) {
|
|
472
|
-
guard let
|
|
492
|
+
guard let jsiRuntime else {
|
|
473
493
|
FatalError.runtimeLost()
|
|
474
494
|
}
|
|
475
|
-
pointee.setExternalMemoryPressure(
|
|
495
|
+
pointee.setExternalMemoryPressure(jsiRuntime, size)
|
|
476
496
|
}
|
|
477
497
|
|
|
478
498
|
// MARK: - Equality
|
|
@@ -7,21 +7,38 @@ internal import jsi
|
|
|
7
7
|
/// this one is a reference type so can be safely captured in closures, passed to other isolation context,
|
|
8
8
|
/// and stored in containers that don't support non-copyable types etc.
|
|
9
9
|
public final class JavaScriptValue: JavaScriptType, Equatable, Escapable {
|
|
10
|
-
|
|
10
|
+
/// Handle to the runtime the value belongs to. `nil` only for runtime-free values (undefined, null,
|
|
11
|
+
/// booleans and numbers).
|
|
12
|
+
internal let runtimeHandle: JavaScriptRuntimeHandle?
|
|
11
13
|
internal let pointee: facebook.jsi.Value
|
|
12
14
|
|
|
13
|
-
///
|
|
14
|
-
///
|
|
15
|
-
internal
|
|
16
|
-
|
|
15
|
+
/// The runtime the value belongs to, or `nil` if it has been deallocated or the value is runtime-free.
|
|
16
|
+
/// Prefer ``jsiRuntime`` on hot paths: it costs no reference counting.
|
|
17
|
+
internal var runtime: JavaScriptRuntime? {
|
|
18
|
+
return runtimeHandle?.runtime
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// The engine runtime the value belongs to, or `nil` if the runtime has been deallocated or the value
|
|
22
|
+
/// is runtime-free.
|
|
23
|
+
internal var jsiRuntime: facebook.jsi.IRuntime? {
|
|
24
|
+
return runtimeHandle?.pointee
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/// Takes ownership of the given JSI value, which belongs to the runtime behind `runtimeHandle`.
|
|
28
|
+
internal init(_ runtimeHandle: JavaScriptRuntimeHandle, _ pointee: consuming facebook.jsi.Value) {
|
|
29
|
+
self.runtimeHandle = runtimeHandle
|
|
17
30
|
self.pointee = pointee
|
|
18
31
|
}
|
|
19
32
|
|
|
20
|
-
/// Takes ownership of the given JSI value
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
33
|
+
/// Takes ownership of the given runtime-free JSI value (undefined, null, a boolean or a number).
|
|
34
|
+
internal init(_ pointee: consuming facebook.jsi.Value) {
|
|
35
|
+
self.runtimeHandle = nil
|
|
36
|
+
self.pointee = pointee
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// Takes ownership of the given JSI value.
|
|
40
|
+
internal init(_ runtime: borrowing JavaScriptRuntime, _ pointee: consuming facebook.jsi.Value) {
|
|
41
|
+
self.runtimeHandle = runtime.handle
|
|
25
42
|
self.pointee = pointee
|
|
26
43
|
}
|
|
27
44
|
|
|
@@ -29,51 +46,51 @@ public final class JavaScriptValue: JavaScriptType, Equatable, Escapable {
|
|
|
29
46
|
/// The `copying:` label keeps this initializer from being picked for temporaries: with a plain
|
|
30
47
|
/// second argument, a non-optional runtime used to win overload resolution over the consuming
|
|
31
48
|
/// initializer above, cloning every freshly returned value instead of taking it over.
|
|
32
|
-
internal init(_ runtime: JavaScriptRuntime, copying pointee: borrowing facebook.jsi.Value) {
|
|
33
|
-
self.
|
|
49
|
+
internal init(_ runtime: borrowing JavaScriptRuntime, copying pointee: borrowing facebook.jsi.Value) {
|
|
50
|
+
self.runtimeHandle = runtime.handle
|
|
34
51
|
self.pointee = facebook.jsi.Value(runtime.pointee, pointee)
|
|
35
52
|
}
|
|
36
53
|
|
|
37
54
|
/// Creates a boolean JS value.
|
|
38
|
-
public init(_ runtime: JavaScriptRuntime, _ bool: Bool) {
|
|
39
|
-
self.
|
|
55
|
+
public init(_ runtime: borrowing JavaScriptRuntime, _ bool: Bool) {
|
|
56
|
+
self.runtimeHandle = runtime.handle
|
|
40
57
|
self.pointee = facebook.jsi.Value(bool)
|
|
41
58
|
}
|
|
42
59
|
|
|
43
60
|
/// Creates a string JS value.
|
|
44
|
-
public init(_ runtime: JavaScriptRuntime, _ string: String) {
|
|
45
|
-
self.
|
|
61
|
+
public init(_ runtime: borrowing JavaScriptRuntime, _ string: String) {
|
|
62
|
+
self.runtimeHandle = runtime.handle
|
|
46
63
|
self.pointee = string.toJSIValue(in: runtime.pointee)
|
|
47
64
|
}
|
|
48
65
|
|
|
49
66
|
/// Creates a BigInt JS value from an Int64.
|
|
50
|
-
public init(_ runtime: JavaScriptRuntime, bigInt: Int64) {
|
|
51
|
-
self.
|
|
67
|
+
public init(_ runtime: borrowing JavaScriptRuntime, bigInt: Int64) {
|
|
68
|
+
self.runtimeHandle = runtime.handle
|
|
52
69
|
self.pointee = facebook.jsi.Value(runtime.pointee, facebook.jsi.BigInt.fromInt64(runtime.pointee, bigInt))
|
|
53
70
|
}
|
|
54
71
|
|
|
55
72
|
/// Creates a BigInt JS value from a UInt64.
|
|
56
|
-
public init(_ runtime: JavaScriptRuntime, bigInt: UInt64) {
|
|
57
|
-
self.
|
|
73
|
+
public init(_ runtime: borrowing JavaScriptRuntime, bigInt: UInt64) {
|
|
74
|
+
self.runtimeHandle = runtime.handle
|
|
58
75
|
self.pointee = facebook.jsi.Value(runtime.pointee, facebook.jsi.BigInt.fromUint64(runtime.pointee, bigInt))
|
|
59
76
|
}
|
|
60
77
|
|
|
61
78
|
/// Creates a JS value from a JS representable.
|
|
62
|
-
public init(_ runtime: JavaScriptRuntime, _ value: JavaScriptRepresentable) {
|
|
63
|
-
self.
|
|
79
|
+
public init(_ runtime: borrowing JavaScriptRuntime, _ value: JavaScriptRepresentable) {
|
|
80
|
+
self.runtimeHandle = runtime.handle
|
|
64
81
|
self.pointee = value.toJavaScriptValue(in: runtime).toJSIValue(in: runtime.pointee)
|
|
65
82
|
}
|
|
66
83
|
|
|
67
84
|
/// Creates a JS value from a JSI representable.
|
|
68
|
-
internal init(_ runtime: JavaScriptRuntime, _ value: JSIRepresentable) {
|
|
69
|
-
self.
|
|
85
|
+
internal init(_ runtime: borrowing JavaScriptRuntime, _ value: JSIRepresentable) {
|
|
86
|
+
self.runtimeHandle = runtime.handle
|
|
70
87
|
self.pointee = value.toJSIValue(in: runtime.pointee)
|
|
71
88
|
}
|
|
72
89
|
|
|
73
90
|
/// Copies the value.
|
|
74
91
|
public func copy() -> JavaScriptValue {
|
|
75
|
-
if let
|
|
76
|
-
return JavaScriptValue(
|
|
92
|
+
if let runtimeHandle, let jsiRuntime = runtimeHandle.pointee {
|
|
93
|
+
return JavaScriptValue(runtimeHandle, facebook.jsi.Value(jsiRuntime, pointee))
|
|
77
94
|
}
|
|
78
95
|
// Some simple value kinds do not require the runtime.
|
|
79
96
|
switch kind {
|
|
@@ -82,9 +99,9 @@ public final class JavaScriptValue: JavaScriptType, Equatable, Escapable {
|
|
|
82
99
|
case .null:
|
|
83
100
|
return .null
|
|
84
101
|
case .bool:
|
|
85
|
-
return .init(
|
|
102
|
+
return .init(facebook.jsi.Value(getBool()))
|
|
86
103
|
case .number:
|
|
87
|
-
return .init(
|
|
104
|
+
return .init(facebook.jsi.Value(getDouble()))
|
|
88
105
|
default:
|
|
89
106
|
FatalError.runtimeLost()
|
|
90
107
|
}
|
|
@@ -137,21 +154,21 @@ public final class JavaScriptValue: JavaScriptType, Equatable, Escapable {
|
|
|
137
154
|
}
|
|
138
155
|
|
|
139
156
|
public func isArray() -> Bool {
|
|
140
|
-
guard let jsiRuntime
|
|
157
|
+
guard let jsiRuntime else {
|
|
141
158
|
FatalError.runtimeLost()
|
|
142
159
|
}
|
|
143
160
|
return pointee.isObject() && pointee.getObject(jsiRuntime).isArray(jsiRuntime)
|
|
144
161
|
}
|
|
145
162
|
|
|
146
163
|
public func isFunction() -> Bool {
|
|
147
|
-
guard let jsiRuntime
|
|
164
|
+
guard let jsiRuntime else {
|
|
148
165
|
FatalError.runtimeLost()
|
|
149
166
|
}
|
|
150
167
|
return pointee.isObject() && pointee.getObject(jsiRuntime).isFunction(jsiRuntime)
|
|
151
168
|
}
|
|
152
169
|
|
|
153
170
|
public func isTypedArray() -> Bool {
|
|
154
|
-
guard let jsiRuntime
|
|
171
|
+
guard let jsiRuntime else {
|
|
155
172
|
FatalError.runtimeLost()
|
|
156
173
|
}
|
|
157
174
|
return pointee.isObject() && expo.isTypedArray(jsiRuntime, pointee.getObject(jsiRuntime))
|
|
@@ -159,7 +176,7 @@ public final class JavaScriptValue: JavaScriptType, Equatable, Escapable {
|
|
|
159
176
|
|
|
160
177
|
/// Checks whether the value is an `ArrayBuffer`.
|
|
161
178
|
public func isArrayBuffer() -> Bool {
|
|
162
|
-
guard let jsiRuntime
|
|
179
|
+
guard let jsiRuntime else {
|
|
163
180
|
FatalError.runtimeLost()
|
|
164
181
|
}
|
|
165
182
|
return pointee.isObject() && pointee.getObject(jsiRuntime).isArrayBuffer(jsiRuntime)
|
|
@@ -258,7 +275,7 @@ public final class JavaScriptValue: JavaScriptType, Equatable, Escapable {
|
|
|
258
275
|
|
|
259
276
|
/// Returns the value as a string, or asserts if not a string.
|
|
260
277
|
public func getString() -> String {
|
|
261
|
-
guard let jsiRuntime
|
|
278
|
+
guard let jsiRuntime else {
|
|
262
279
|
FatalError.runtimeLost()
|
|
263
280
|
}
|
|
264
281
|
assert(isString(), "Value is not a string")
|
|
@@ -276,20 +293,20 @@ public final class JavaScriptValue: JavaScriptType, Equatable, Escapable {
|
|
|
276
293
|
|
|
277
294
|
/// Returns the value as an object, or asserts if not an object.
|
|
278
295
|
public func getObject() -> JavaScriptObject {
|
|
279
|
-
guard let
|
|
296
|
+
guard let runtimeHandle, let jsiRuntime = runtimeHandle.pointee else {
|
|
280
297
|
FatalError.runtimeLost()
|
|
281
298
|
}
|
|
282
299
|
assert(isObject(), "Value is not an object")
|
|
283
|
-
return JavaScriptObject(
|
|
300
|
+
return JavaScriptObject(runtimeHandle, pointee.getObject(jsiRuntime))
|
|
284
301
|
}
|
|
285
302
|
|
|
286
303
|
/// Returns the value as an array, or asserts if not an array.
|
|
287
304
|
public func getArray() -> JavaScriptArray {
|
|
288
|
-
guard let
|
|
305
|
+
guard let runtimeHandle, let jsiRuntime = runtimeHandle.pointee else {
|
|
289
306
|
FatalError.runtimeLost()
|
|
290
307
|
}
|
|
291
308
|
assert(isArray(), "Value is not an array")
|
|
292
|
-
return JavaScriptArray(
|
|
309
|
+
return JavaScriptArray(runtimeHandle, pointee.getObject(jsiRuntime).getArray(jsiRuntime))
|
|
293
310
|
}
|
|
294
311
|
|
|
295
312
|
/// Returns the value as a function, or asserts if not a function.
|
|
@@ -426,7 +443,7 @@ public final class JavaScriptValue: JavaScriptType, Equatable, Escapable {
|
|
|
426
443
|
|
|
427
444
|
/// Returns a string representing the value. Same as calling `toString()` in JS.
|
|
428
445
|
public func toString() -> String {
|
|
429
|
-
guard let jsiRuntime
|
|
446
|
+
guard let jsiRuntime else {
|
|
430
447
|
FatalError.runtimeLost()
|
|
431
448
|
}
|
|
432
449
|
return String(jsiString: pointee.toString(jsiRuntime), in: jsiRuntime)
|
|
@@ -536,8 +553,8 @@ public final class JavaScriptValue: JavaScriptType, Equatable, Escapable {
|
|
|
536
553
|
}
|
|
537
554
|
|
|
538
555
|
internal func asJSIValue() -> facebook.jsi.Value {
|
|
539
|
-
if let
|
|
540
|
-
return facebook.jsi.Value(
|
|
556
|
+
if let jsiRuntime {
|
|
557
|
+
return facebook.jsi.Value(jsiRuntime, pointee)
|
|
541
558
|
}
|
|
542
559
|
// Some simple value kinds do not require the runtime.
|
|
543
560
|
switch kind {
|
|
@@ -597,7 +614,7 @@ public final class JavaScriptValue: JavaScriptType, Equatable, Escapable {
|
|
|
597
614
|
|
|
598
615
|
/// Tests whether two values are strictly equal, according to https://262.ecma-international.org/11.0/#sec-strict-equality-comparison
|
|
599
616
|
public func isEqual(to another: JavaScriptValue) -> Bool {
|
|
600
|
-
if let jsiRuntime =
|
|
617
|
+
if let jsiRuntime = jsiRuntime ?? another.jsiRuntime {
|
|
601
618
|
return facebook.jsi.Value.strictEquals(jsiRuntime, pointee, another.pointee)
|
|
602
619
|
}
|
|
603
620
|
// Some types don't have to be tied to any runtime. Since `strictEquals` needs a runtime, we need to handle this case ourselves.
|
|
@@ -659,20 +676,20 @@ public final class JavaScriptValue: JavaScriptType, Equatable, Escapable {
|
|
|
659
676
|
/// This is a lightweight way to create a boolean true value that can be used in contexts
|
|
660
677
|
/// where a runtime is not available or needed.
|
|
661
678
|
public static func `true`() -> JavaScriptValue {
|
|
662
|
-
return JavaScriptValue(
|
|
679
|
+
return JavaScriptValue(facebook.jsi.Value(true))
|
|
663
680
|
}
|
|
664
681
|
|
|
665
682
|
/// This is a lightweight way to create a boolean false value that can be used in contexts
|
|
666
683
|
/// where a runtime is not available or needed.
|
|
667
684
|
public static func `false`() -> JavaScriptValue {
|
|
668
|
-
return JavaScriptValue(
|
|
685
|
+
return JavaScriptValue(facebook.jsi.Value(false))
|
|
669
686
|
}
|
|
670
687
|
|
|
671
688
|
/// This is a lightweight way to create a numeric value that can be used in contexts
|
|
672
689
|
/// where a runtime is not available or needed. JavaScript numbers are represented
|
|
673
690
|
/// as double-precision floating-point values following the IEEE 754 standard.
|
|
674
691
|
public static func number(_ number: Double) -> JavaScriptValue {
|
|
675
|
-
return JavaScriptValue(
|
|
692
|
+
return JavaScriptValue(facebook.jsi.Value(number))
|
|
676
693
|
}
|
|
677
694
|
|
|
678
695
|
public static func representing(value: JavaScriptRepresentable, in runtime: JavaScriptRuntime) -> JavaScriptValue {
|
|
@@ -725,6 +742,6 @@ extension JavaScriptValue {
|
|
|
725
742
|
// Shared instances behind `JavaScriptValue.undefined` and `JavaScriptValue.null`; see the comment on
|
|
726
743
|
// those accessors for why these are globals.
|
|
727
744
|
@usableFromInline
|
|
728
|
-
internal let sharedUndefinedValue = JavaScriptValue(
|
|
745
|
+
internal let sharedUndefinedValue = JavaScriptValue(facebook.jsi.Value.undefined())
|
|
729
746
|
@usableFromInline
|
|
730
|
-
internal let sharedNullValue = JavaScriptValue(
|
|
747
|
+
internal let sharedNullValue = JavaScriptValue(facebook.jsi.Value.null())
|
|
@@ -25,6 +25,16 @@ extension String {
|
|
|
25
25
|
self = result
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/// Builds a Swift `String` from a `jsi::PropNameID` the same way as `init(jsiString:in:)`, reading
|
|
29
|
+
/// the engine's internal representation without materializing a `std::string` first.
|
|
30
|
+
internal init(jsiPropNameID: borrowing facebook.jsi.PropNameID, in runtime: facebook.jsi.IRuntime) {
|
|
31
|
+
var result = ""
|
|
32
|
+
withUnsafeMutablePointer(to: &result) { resultPtr in
|
|
33
|
+
expo.getPropNameIdData(runtime, jsiPropNameID, UnsafeMutableRawPointer(resultPtr), appendEngineStringChunk)
|
|
34
|
+
}
|
|
35
|
+
self = result
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
/// Builds a `jsi::PropNameID` from the string's UTF-8 bytes. This is how every String-keyed
|
|
29
39
|
/// property API turns its name into a key: JSI's `const char*` overloads treat the bytes as ASCII
|
|
30
40
|
/// and would mangle any non-ASCII name.
|
|
@@ -26,7 +26,7 @@ public:
|
|
|
26
26
|
jsi::Value result;
|
|
27
27
|
// If the Swift getter stored a pending error, rethrow its JSError directly
|
|
28
28
|
// to preserve all properties (message, code, stack, etc.).
|
|
29
|
-
if (_callbacks.get(name
|
|
29
|
+
if (_callbacks.get(name, result)) {
|
|
30
30
|
if (auto *error = CppError::getCurrent()) {
|
|
31
31
|
throw error->release();
|
|
32
32
|
}
|
|
@@ -39,7 +39,7 @@ public:
|
|
|
39
39
|
// `jsi::JSError` directly and the `CppError` check below is never reached.
|
|
40
40
|
// For writable host objects, a throwing Swift setter routes its error through
|
|
41
41
|
// `CppError`'s thread-local slot, which we drain and rethrow here.
|
|
42
|
-
if (_callbacks.set(runtime, name
|
|
42
|
+
if (_callbacks.set(runtime, name, value)) {
|
|
43
43
|
if (auto *error = CppError::getCurrent()) {
|
|
44
44
|
throw error->release();
|
|
45
45
|
}
|