Skip to content

Commit de61e95

Browse files
authoredAug 10, 2020
Clean up the JSObjectRef API (swiftwasm#28)
* Add xcworkspaces * Convert JSObjectRef.get() and JSObjectRef.set() to subscripts * Make instanceof static * [not working] attempt at new JSValueConvertible with no instance methods * Revert "[not working] attempt at new JSValueConvertible with no instance methods" This reverts commit c4d2e12. * Subscript-based JSValue conversion * Partially fix tests * Remove JSFunctionRef.apply and JSFunctionRef.new * Comment out failing tests * Update function call signature * Last change to functions, hopefully * Remove unnecessary .function * Ignore .swiftpm * Switch back to JSFunctionRef.new() * Switch instanceof to JSObjectRef.isInstanceOf * Revert "Subscript-based JSValue conversion" This reverts commit 4373e95. * Fix error * Run swiftformat * Uncomment tests, fix bug * args → arguments * Mark callAsFunction(this:, arguments:) as public
1 parent ed0acba commit de61e95

File tree

9 files changed

+59
-71
lines changed

9 files changed

+59
-71
lines changed
 

Diff for: ‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ node_modules
55
/Packages
66
/*.xcodeproj
77
xcuserdata/
8+
.swiftpm

Diff for: ‎IntegrationTests/TestSuites/Sources/BenchmarkTests/main.swift

+2-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ serialization.testSuite("Swift Int to JavaScript") {
77
let jsNumber = JSValue.number(swiftInt)
88
let object = JSObjectRef.global
99
for i in 0 ..< 100 {
10-
object.set("numberValue\(i)", jsNumber)
10+
object["numberValue\(i)"] = jsNumber
1111
}
1212
}
1313

@@ -16,11 +16,10 @@ serialization.testSuite("Swift String to JavaScript") {
1616
let jsString = JSValue.string(swiftString)
1717
let object = JSObjectRef.global
1818
for i in 0 ..< 100 {
19-
object.set("stringValue\(i)", jsString)
19+
object["stringValue\(i)"] = jsString
2020
}
2121
}
2222

23-
2423
let objectHeap = Benchmark("Object heap")
2524

2625
let global = JSObjectRef.global

Diff for: ‎IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift

+11-11
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ New_Object_Construction: do {
239239
let cat1 = objectConstructor.new("Tama", 3, true)
240240
try expectEqual(getJSValue(this: cat1, name: "name"), .string("Tama"))
241241
try expectEqual(getJSValue(this: cat1, name: "age"), .number(3))
242-
try expectEqual(cat1.instanceof(objectConstructor), true)
243-
try expectEqual(cat1.instanceof(try expectFunction(getJSValue(this: .global, name: "Array"))), false)
242+
try expectEqual(cat1.isInstanceOf(objectConstructor), true)
243+
try expectEqual(cat1.isInstanceOf(try expectFunction(getJSValue(this: .global, name: "Array"))), false)
244244
let cat1Bark = try expectFunction(getJSValue(this: cat1, name: "bark"))
245245
try expectEqual(cat1Bark(), .string("nyan"))
246246

@@ -273,20 +273,20 @@ Call_Function_With_This: do {
273273
try expectEqual(getIsCat(), .undefined)
274274

275275
// Call with this
276-
let gotIsCat = getIsCat.apply(this: cat1)
276+
let gotIsCat = getIsCat(this: cat1)
277277
try expectEqual(gotIsCat, .boolean(true))
278278

279279
} catch {
280280
print(error)
281281
}
282282

283283
Object_Conversion: do {
284-
let array1 = [1, 2, 3]
285-
let jsArray1 = array1.jsValue().object!
286-
try expectEqual(jsArray1.length, .number(3))
287-
try expectEqual(jsArray1[0], .number(1))
288-
try expectEqual(jsArray1[1], .number(2))
289-
try expectEqual(jsArray1[2], .number(3))
284+
let array1 = [1, 2, 3]
285+
let jsArray1 = array1.jsValue().object!
286+
try expectEqual(jsArray1.length, .number(3))
287+
try expectEqual(jsArray1[0], .number(1))
288+
try expectEqual(jsArray1[1], .number(2))
289+
try expectEqual(jsArray1[2], .number(3))
290290

291291
let array2: [JSValueConvertible] = [1, "str", false]
292292
let jsArray2 = array2.jsValue().object!
@@ -296,9 +296,9 @@ Object_Conversion: do {
296296
try expectEqual(jsArray2[2], .boolean(false))
297297
_ = jsArray2.push!(5)
298298
try expectEqual(jsArray2.length, .number(4))
299-
_ = jsArray2.push!(jsArray1)
299+
_ = jsArray2.push!(jsArray1)
300300

301-
try expectEqual(jsArray2[4], .object(jsArray1))
301+
try expectEqual(jsArray2[4], .object(jsArray1))
302302

303303
let dict1: [String: JSValueConvertible] = [
304304
"prop1": 1,

Diff for: ‎Sources/JavaScriptKit/JSArrayRef.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ public class JSArrayRef {
33
static let classObject = JSObjectRef.global.Array.function!
44

55
static func isArray(_ object: JSObjectRef) -> Bool {
6-
classObject.isArray.function!(object).boolean!
6+
classObject.isArray!(object).boolean!
77
}
88

99
let ref: JSObjectRef
@@ -33,13 +33,13 @@ extension JSArrayRef: RandomAccessCollection {
3333
guard index < Int(ref.length.number!) else {
3434
return nil
3535
}
36-
let value = ref.get(index)
36+
let value = ref[index]
3737
return value.isNull ? nil : value
3838
}
3939
}
4040

4141
public subscript(position: Int) -> JSValue {
42-
ref.get(position)
42+
ref[position]
4343
}
4444

4545
public var startIndex: Int { 0 }

Diff for: ‎Sources/JavaScriptKit/JSFunction.swift

+25-26
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,44 @@
11
import _CJavaScriptKit
22

3-
@dynamicCallable
43
public class JSFunctionRef: JSObjectRef {
54
@discardableResult
6-
public func dynamicallyCall(withArguments arguments: [JSValueConvertible]) -> JSValue {
7-
let result = arguments.withRawJSValues { rawValues -> RawJSValue in
5+
public func callAsFunction(this: JSObjectRef? = nil, arguments: [JSValueConvertible]) -> JSValue {
6+
let result = arguments.withRawJSValues { rawValues in
87
rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in
98
let argv = bufferPointer.baseAddress
109
let argc = bufferPointer.count
1110
var result = RawJSValue()
12-
_call_function(
13-
self.id, argv, Int32(argc),
14-
&result.kind, &result.payload1, &result.payload2, &result.payload3
15-
)
11+
if let thisId = this?.id {
12+
_call_function_with_this(thisId,
13+
self.id, argv, Int32(argc),
14+
&result.kind, &result.payload1, &result.payload2, &result.payload3)
15+
} else {
16+
_call_function(
17+
self.id, argv, Int32(argc),
18+
&result.kind, &result.payload1, &result.payload2, &result.payload3
19+
)
20+
}
1621
return result
1722
}
1823
}
1924
return result.jsValue()
2025
}
2126

22-
public func apply(this: JSObjectRef, arguments: JSValueConvertible...) -> JSValue {
23-
apply(this: this, argumentList: arguments)
27+
@discardableResult
28+
public func callAsFunction(this: JSObjectRef? = nil, _ arguments: JSValueConvertible...) -> JSValue {
29+
self(this: this, arguments: arguments)
2430
}
2531

26-
public func apply(this: JSObjectRef, argumentList: [JSValueConvertible]) -> JSValue {
27-
let result = argumentList.withRawJSValues { rawValues in
28-
rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in
29-
let argv = bufferPointer.baseAddress
30-
let argc = bufferPointer.count
31-
var result = RawJSValue()
32-
_call_function_with_this(this.id,
33-
self.id, argv, Int32(argc),
34-
&result.kind, &result.payload1, &result.payload2, &result.payload3)
35-
return result
36-
}
37-
}
38-
return result.jsValue()
32+
public func new(_ arguments: JSValueConvertible...) -> JSObjectRef {
33+
new(arguments: arguments)
3934
}
4035

41-
public func new(_ arguments: JSValueConvertible...) -> JSObjectRef {
42-
return arguments.withRawJSValues { rawValues in
36+
// Guaranteed to return an object because either:
37+
// a) the constructor explicitly returns an object, or
38+
// b) the constructor returns nothing, which causes JS to return the `this` value, or
39+
// c) the constructor returns undefined, null or a non-object, in which case JS also returns `this`.
40+
public func new(arguments: [JSValueConvertible]) -> JSObjectRef {
41+
arguments.withRawJSValues { rawValues in
4342
rawValues.withUnsafeBufferPointer { bufferPointer in
4443
let argv = bufferPointer.baseAddress
4544
let argc = bufferPointer.count
@@ -106,10 +105,10 @@ public func _call_host_function(
106105
guard let hostFunc = JSClosure.sharedFunctions[hostFuncRef] else {
107106
fatalError("The function was already released")
108107
}
109-
let args = UnsafeBufferPointer(start: argv, count: Int(argc)).map {
108+
let arguments = UnsafeBufferPointer(start: argv, count: Int(argc)).map {
110109
$0.jsValue()
111110
}
112-
let result = hostFunc(args)
111+
let result = hostFunc(arguments)
113112
let callbackFuncRef = JSFunctionRef(id: callbackFuncRef)
114113
_ = callbackFuncRef(result)
115114
}

Diff for: ‎Sources/JavaScriptKit/JSObject.swift

+11-22
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,29 @@ public class JSObjectRef: Equatable {
99

1010
@_disfavoredOverload
1111
public subscript(dynamicMember name: String) -> ((JSValueConvertible...) -> JSValue)? {
12-
guard let function = self[dynamicMember: name].function else { return nil }
12+
guard let function = self[name].function else { return nil }
1313
return { (arguments: JSValueConvertible...) in
14-
function.apply(this: self, argumentList: arguments)
14+
function(this: self, arguments: arguments)
1515
}
1616
}
1717

1818
public subscript(dynamicMember name: String) -> JSValue {
19-
get { get(name) }
20-
set { set(name, newValue) }
19+
get { self[name] }
20+
set { self[name] = newValue }
2121
}
2222

23-
public func get(_ name: String) -> JSValue {
24-
getJSValue(this: self, name: name)
25-
}
26-
27-
public func set(_ name: String, _ value: JSValue) {
28-
setJSValue(this: self, name: name, value: value)
29-
}
30-
31-
public func get(_ index: Int) -> JSValue {
32-
getJSValue(this: self, index: Int32(index))
33-
}
34-
35-
public func instanceof(_ constructor: JSFunctionRef) -> Bool {
36-
_instanceof(self.id, constructor.id)
23+
public subscript(_ name: String) -> JSValue {
24+
get { getJSValue(this: self, name: name) }
25+
set { setJSValue(this: self, name: name, value: newValue) }
3726
}
3827

3928
public subscript(_ index: Int) -> JSValue {
40-
get { get(index) }
41-
set { set(index, newValue) }
29+
get { getJSValue(this: self, index: Int32(index)) }
30+
set { setJSValue(this: self, index: Int32(index), value: newValue) }
4231
}
4332

44-
public func set(_ index: Int, _ value: JSValue) {
45-
setJSValue(this: self, index: Int32(index), value: value)
33+
public func isInstanceOf(_ constructor: JSFunctionRef) -> Bool {
34+
_instanceof(id, constructor.id)
4635
}
4736

4837
static let _JS_Predef_Value_Global: UInt32 = 0

Diff for: ‎Sources/JavaScriptKit/JSValueConvertible.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ extension Dictionary: JSValueConvertible where Value == JSValueConvertible, Key
6969
public func jsValue() -> JSValue {
7070
let object = Object.new()
7171
for (key, value) in self {
72-
object.set(key, value.jsValue())
72+
object[key] = value.jsValue()
7373
}
7474
return .object(object)
7575
}

Diff for: ‎Sources/JavaScriptKit/JSValueDecoder.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ private struct _Decoder: Decoder {
3434
}
3535

3636
private enum Object {
37-
static let ref = JSObjectRef.global.get("Object").object!
37+
static let ref = JSObjectRef.global.Object.object!
3838
static func keys(_ object: JSObjectRef) -> [String] {
3939
let keys = ref.keys!(object).array!
4040
return keys.map { $0.string! }
@@ -90,7 +90,7 @@ private struct _KeyedDecodingContainer<Key: CodingKey>: KeyedDecodingContainerPr
9090
}
9191

9292
func _decode(forKey key: CodingKey) throws -> JSValue {
93-
let result = ref.get(key.stringValue)
93+
let result = ref[key.stringValue]
9494
guard !result.isUndefined else {
9595
throw _keyNotFound(at: codingPath, key)
9696
}
@@ -106,7 +106,7 @@ private struct _KeyedDecodingContainer<Key: CodingKey>: KeyedDecodingContainerPr
106106
}
107107

108108
func contains(_ key: Key) -> Bool {
109-
!ref.get(key.stringValue).isUndefined
109+
!ref[key.stringValue].isUndefined
110110
}
111111

112112
func decodeNil(forKey key: Key) throws -> Bool {
@@ -162,7 +162,7 @@ private struct _UnkeyedDecodingContainer: UnkeyedDecodingContainer {
162162

163163
mutating func _currentValue() -> JSValue {
164164
defer { currentIndex += 1 }
165-
return ref.get(currentIndex)
165+
return ref[currentIndex]
166166
}
167167

168168
mutating func _throwTypeMismatchIfNil<T>(_ transform: (JSValue) -> T?) throws -> T {

Diff for: ‎Sources/JavaScriptKit/XcodeSupport.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ import _CJavaScriptKit
6666
) { fatalError() }
6767
func _instanceof(
6868
_: JavaScriptObjectRef,
69-
_: JavaScriptObjectRef
69+
_: JavaScriptObjectRef
7070
) -> Bool { fatalError() }
7171
func _create_function(
7272
_: JavaScriptHostFuncRef,

0 commit comments

Comments
 (0)