forked from swiftwasm/JavaScriptKit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathJSFunction.swift
115 lines (100 loc) · 3.98 KB
/
JSFunction.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import _CJavaScriptKit
@dynamicCallable
public class JSFunctionRef: JSObjectRef {
@discardableResult
public func dynamicallyCall(withArguments arguments: [JSValueConvertible]) -> JSValue {
let result = arguments.withRawJSValues { rawValues -> RawJSValue in
rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in
let argv = bufferPointer.baseAddress
let argc = bufferPointer.count
var result = RawJSValue()
_call_function(
self.id, argv, Int32(argc),
&result.kind, &result.payload1, &result.payload2, &result.payload3
)
return result
}
}
return result.jsValue()
}
public func apply(this: JSObjectRef, arguments: JSValueConvertible...) -> JSValue {
apply(this: this, argumentList: arguments)
}
public func apply(this: JSObjectRef, argumentList: [JSValueConvertible]) -> JSValue {
let result = argumentList.withRawJSValues { rawValues in
rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in
let argv = bufferPointer.baseAddress
let argc = bufferPointer.count
var result = RawJSValue()
_call_function_with_this(this.id,
self.id, argv, Int32(argc),
&result.kind, &result.payload1, &result.payload2, &result.payload3)
return result
}
}
return result.jsValue()
}
public func new(_ arguments: JSValueConvertible...) -> JSObjectRef {
return arguments.withRawJSValues { rawValues in
rawValues.withUnsafeBufferPointer { bufferPointer in
let argv = bufferPointer.baseAddress
let argc = bufferPointer.count
var resultObj = JavaScriptObjectRef()
_call_new(
self.id, argv, Int32(argc),
&resultObj
)
return JSObjectRef(id: resultObj)
}
}
}
@available(*, unavailable, message: "Please use JSClosure instead")
public static func from(_: @escaping ([JSValue]) -> JSValue) -> JSFunctionRef {
fatalError("unavailable")
}
override public func jsValue() -> JSValue {
.function(self)
}
}
public class JSClosure: JSFunctionRef {
static var sharedFunctions: [JavaScriptHostFuncRef: ([JSValue]) -> JSValue] = [:]
private var hostFuncRef: JavaScriptHostFuncRef = 0
public init(_ body: @escaping ([JSValue]) -> JSValue) {
super.init(id: 0)
let objectId = ObjectIdentifier(self)
let funcRef = JavaScriptHostFuncRef(bitPattern: Int32(objectId.hashValue))
Self.sharedFunctions[funcRef] = body
var objectRef: JavaScriptObjectRef = 0
_create_function(funcRef, &objectRef)
hostFuncRef = funcRef
id = objectRef
}
public func release() {
Self.sharedFunctions[hostFuncRef] = nil
}
}
@_cdecl("swjs_prepare_host_function_call")
public func _prepare_host_function_call(_ argc: Int32) -> UnsafeMutableRawPointer {
let argumentSize = MemoryLayout<RawJSValue>.size * Int(argc)
return malloc(Int(argumentSize))!
}
@_cdecl("swjs_cleanup_host_function_call")
public func _cleanup_host_function_call(_ pointer: UnsafeMutableRawPointer) {
free(pointer)
}
@_cdecl("swjs_call_host_function")
public func _call_host_function(
_ hostFuncRef: JavaScriptHostFuncRef,
_ argv: UnsafePointer<RawJSValue>, _ argc: Int32,
_ callbackFuncRef: JavaScriptObjectRef
) {
guard let hostFunc = JSClosure.sharedFunctions[hostFuncRef] else {
fatalError("The function was already released")
}
let args = UnsafeBufferPointer(start: argv, count: Int(argc)).map {
$0.jsValue()
}
let result = hostFunc(args)
let callbackFuncRef = JSFunctionRef(id: callbackFuncRef)
_ = callbackFuncRef(result)
}