Skip to content

Commit 7f1772e

Browse files
authored
Clean up use of closure property wrappers (#59)
This changes improves compatibility of the WebAPIKit library with Embedded Swift. Unsupported concurrency code is excluded when concurrency is not available, including the use of async sequences. Use of closure patterns is cleaned up to use getters and setters directly instead of property wrappers, which reduces binary code size when Embedded Swift is used.
1 parent 4fbb046 commit 7f1772e

File tree

4 files changed

+28
-17
lines changed

4 files changed

+28
-17
lines changed

Sources/WebIDLToSwift/ClosurePattern.swift

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
struct ClosurePattern: SwiftRepresentable, Equatable, Hashable, Comparable {
22
static func < (lhs: ClosurePattern, rhs: ClosurePattern) -> Bool {
3-
lhs.name.source < rhs.name.source
3+
lhs.closureType.source < rhs.closureType.source
44
}
55

66
let nullable: Bool
@@ -22,16 +22,16 @@ struct ClosurePattern: SwiftRepresentable, Equatable, Hashable, Comparable {
2222
return nullable ? "(\(closure))?" : closure
2323
}
2424

25-
private var getter: SwiftSource {
25+
func getter(name: SwiftSource) -> SwiftSource {
2626
let getFunction: SwiftSource
2727
if nullable {
2828
getFunction = """
29-
guard let function = jsObject[name].function else {
29+
guard let function = jsObject[\(name)].function else {
3030
return nil
3131
}
3232
"""
3333
} else {
34-
getFunction = "let function = jsObject[name].function!"
34+
getFunction = "let function = jsObject[\(name)].function!"
3535
}
3636
let call: SwiftSource = "function(\(sequence: indexes.map { "_toJSValue($\($0))" }))"
3737
let closureBody: SwiftSource
@@ -66,15 +66,15 @@ struct ClosurePattern: SwiftRepresentable, Equatable, Hashable, Comparable {
6666
"""
6767
}
6868

69-
private var setter: SwiftSource {
70-
let setClosure: SwiftSource = "jsObject[name] = \(jsClosureWrapper(name: "newValue"))"
69+
func setter(name: SwiftSource) -> SwiftSource {
70+
let setClosure: SwiftSource = "jsObject[\(name)] = \(jsClosureWrapper(name: "newValue"))"
7171

7272
if nullable {
7373
return """
7474
if let newValue = newValue {
7575
\(setClosure)
7676
} else {
77-
jsObject[name] = .null
77+
jsObject[\(name)] = .null
7878
}
7979
"""
8080
} else {
@@ -121,6 +121,7 @@ struct ClosurePattern: SwiftRepresentable, Equatable, Hashable, Comparable {
121121
"""
122122
}
123123

124+
124125
var toJSValue: SwiftSource {
125126
let escaping: SwiftSource = nullable ? "" : "@escaping"
126127
return """
@@ -132,7 +133,6 @@ struct ClosurePattern: SwiftRepresentable, Equatable, Hashable, Comparable {
132133

133134
var swiftRepresentation: SwiftSource {
134135
"""
135-
\(propertyWrapper)
136136
\(toJSValue)
137137
"""
138138
}

Sources/WebIDLToSwift/IDLBuilder.swift

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Foundation
22
import WebIDL
33

44
enum IDLBuilder {
5-
static let basicDependencies = ["ECMAScript", "JavaScriptKit", "JavaScriptEventLoop"]
5+
static let basicDependencies = ["ECMAScript", "JavaScriptKit"]
66
static let optionalDependencies = ["JavaScriptEventLoop"]
77

88
static let preamble = """
@@ -95,9 +95,8 @@ enum IDLBuilder {
9595
}
9696

9797
static func generateClosureTypes() throws -> SwiftSource {
98-
print("Generating closure property wrappers...")
98+
print("Generating closure wrappers...")
9999
return """
100-
/* variadic generics please */
101100
\(lines: ModuleState.closurePatterns.sorted().map(\.swiftRepresentation))
102101
"""
103102
}

Sources/WebIDLToSwift/MergeDeclarations.swift

-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ enum DeclarationMerger {
77
"CustomElementConstructor",
88
"ArrayBufferView",
99
"RotationMatrixType",
10-
// Mapped to `Int32` manually. This can't be represented as `Int64` due to `BigInt` representation on JS side,
11-
// but as a pointer it can't be represented as floating point number either.
12-
"GLintptr",
1310
]
1411
static let ignoredIncludeTargets: Set<String> = ["WorkerNavigator"]
1512
static let validExposures: Set<String> = ["Window"]

Sources/WebIDLToSwift/WebIDL+SwiftRepresentation.swift

+18-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ extension IDLArgument: SwiftRepresentable {
55
let type: SwiftSource
66
if variadic {
77
type = "\(idlType)..."
8-
} else if idlType.isFunction, !optional, !idlType.nullable {
8+
} else if idlType.closurePattern != nil && !optional && !idlType.nullable {
99
type = "@escaping \(idlType)"
1010
} else {
1111
type = "\(idlType)"
@@ -23,7 +23,7 @@ extension IDLArgument: SwiftRepresentable {
2323
}
2424
}
2525

26-
extension IDLAttribute: SwiftRepresentable, Initializable {
26+
extension IDLAttribute: SwiftRepresentable {
2727
private var wrapperName: SwiftSource {
2828
"_\(raw: name)"
2929
}
@@ -247,12 +247,16 @@ extension MergedInterface: SwiftRepresentable {
247247
]
248248
let access: SwiftSource = openClasses.contains(name) ? "open" : "public"
249249

250+
let hasAsyncSequence: Bool
250251
let header: SwiftSource
251252
if partial {
252253
header = "public extension \(name)"
254+
hasAsyncSequence = false
253255
} else {
254256
let inheritance = (parentClasses.isEmpty ? ["JSBridgedClass"] : parentClasses) + mixins
257+
.filter { $0 != "AsyncSequence" }
255258
header = "\(access) class \(name): \(sequence: inheritance.map(SwiftSource.init(_:)))"
259+
hasAsyncSequence = mixins.contains { $0 == "AsyncSequence" }
256260
}
257261

258262
return """
@@ -269,13 +273,22 @@ extension MergedInterface: SwiftRepresentable {
269273
""" : "")
270274
271275
public required init(unsafelyWrapping jsObject: JSObject) {
272-
\(memberInits.joined(separator: "\n"))
273276
\(parentClasses.isEmpty ? "self.jsObject = jsObject" : "super.init(unsafelyWrapping: jsObject)")
274277
}
275278
""")
276279
277280
\(body)
278281
}
282+
283+
\(hasAsyncSequence ?
284+
"""
285+
#if canImport(JavaScriptEventLoop)
286+
public extension \(name): AsyncSequence {}
287+
#endif
288+
""" :
289+
""
290+
)
291+
279292
"""
280293
}
281294

@@ -380,11 +393,13 @@ extension IDLIterableDeclaration: SwiftRepresentable, Initializable {
380393
var swiftRepresentation: SwiftSource {
381394
if async {
382395
return """
396+
#if canImport(JavaScriptEventLoop)
383397
public typealias Element = \(idlType[0])
384398
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
385399
public func makeAsyncIterator() -> ValueIterableAsyncIterator<\(ModuleState.className)> {
386400
ValueIterableAsyncIterator(sequence: self)
387401
}
402+
#endif
388403
"""
389404
} else {
390405
return """

0 commit comments

Comments
 (0)