@@ -113,3 +113,67 @@ func _call_host_function_impl(
113
113
let callbackFuncRef = JSFunction ( id: callbackFuncRef)
114
114
_ = callbackFuncRef ( result)
115
115
}
116
+
117
+ // MARK: - Legacy Closure Types
118
+
119
+ /// `JSOneshotClosure` is a JavaScript function that can be called only once.
120
+ /// It is recommended to use `JSClosure` instead if your target runtimes support `FinalizationRegistry`.
121
+ public class JSOneshotClosure : JSObject , JSClosureProtocol {
122
+ private var hostFuncRef : JavaScriptHostFuncRef = 0
123
+
124
+ public init ( _ body: @escaping ( [ JSValue ] ) -> JSValue ) {
125
+ // 1. Fill `id` as zero at first to access `self` to get `ObjectIdentifier`.
126
+ super. init ( id: 0 )
127
+ let objectId = ObjectIdentifier ( self )
128
+ let funcRef = JavaScriptHostFuncRef ( bitPattern: Int32 ( objectId. hashValue) )
129
+ // 2. Retain the given body in static storage by `funcRef`.
130
+ sharedClosures [ funcRef] = {
131
+ defer { self . release ( ) }
132
+ return body ( $0)
133
+ }
134
+ // 3. Create a new JavaScript function which calls the given Swift function.
135
+ var objectRef : JavaScriptObjectRef = 0
136
+ _create_function ( funcRef, & objectRef)
137
+
138
+ hostFuncRef = funcRef
139
+ id = objectRef
140
+ }
141
+
142
+ /// Release this function resource.
143
+ /// After calling `release`, calling this function from JavaScript will fail.
144
+ public func release( ) {
145
+ sharedClosures [ hostFuncRef] = nil
146
+ }
147
+ }
148
+
149
+ public class JSUnretainedClosure : JSObject , JSClosureProtocol {
150
+ private var hostFuncRef : JavaScriptHostFuncRef = 0
151
+ var isReleased : Bool = false
152
+
153
+ public init ( _ body: @escaping ( [ JSValue ] ) -> JSValue ) {
154
+ // 1. Fill `id` as zero at first to access `self` to get `ObjectIdentifier`.
155
+ super. init ( id: 0 )
156
+ let objectId = ObjectIdentifier ( self )
157
+ let funcRef = JavaScriptHostFuncRef ( bitPattern: Int32 ( objectId. hashValue) )
158
+ // 2. Retain the given body in static storage by `funcRef`.
159
+ sharedClosures [ funcRef] = body
160
+ // 3. Create a new JavaScript function which calls the given Swift function.
161
+ var objectRef : JavaScriptObjectRef = 0
162
+ _create_function ( funcRef, & objectRef)
163
+
164
+ hostFuncRef = funcRef
165
+ id = objectRef
166
+ }
167
+
168
+ public func release( ) {
169
+ isReleased = true
170
+ sharedClosures [ hostFuncRef] = nil
171
+ }
172
+
173
+ deinit {
174
+ guard isReleased else {
175
+ // Safari doesn't support `FinalizationRegistry`, so we cannot automatically manage the lifetime of Swift objects
176
+ fatalError ( " release() must be called on JSClosure objects manually before they are deallocated " )
177
+ }
178
+ }
179
+ }
0 commit comments