Skip to content

Commit

Permalink
Rename (Type|Param)Projection to (Type|Param)Binding (#473)
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanlabelle authored Jan 8, 2025
1 parent 7b87e31 commit 0f83c59
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 99 deletions.
Original file line number Diff line number Diff line change
@@ -1,44 +1,45 @@
import CodeWriters
import DotNetMetadata

public struct ParamProjection {
/// Describes how a WinMD function parameter gets mapped to a Swift function parameter and vice-versa.
public struct ParamBinding {
public enum PassBy: Equatable {
case value
case reference(in: Bool, out: Bool, optional: Bool)
case `return`(nullAsError: Bool)
}

public let name: String
public let typeProjection: TypeProjection
public let typeBinding: TypeBinding
public let passBy: PassBy

public init(name: String, typeProjection: TypeProjection, passBy: PassBy) {
public init(name: String, typeBinding: TypeBinding, passBy: PassBy) {
self.name = name
self.typeProjection = typeProjection
self.typeBinding = typeBinding
self.passBy = passBy
}

public var bindingType: SwiftType { typeProjection.bindingType }
public var bindingType: SwiftType { typeBinding.bindingType }

public var swiftType: SwiftType {
if case .return(nullAsError: true) = passBy { return typeProjection.swiftType.unwrapOptional() }
return typeProjection.swiftType
if case .return(nullAsError: true) = passBy { return typeBinding.swiftType.unwrapOptional() }
return typeBinding.swiftType
}

public var abiBindingName: String { name + "_abi" }
public var swiftBindingName: String { name + "_swift" }
public var isArray: Bool { typeProjection.kind == .array }
public var isArray: Bool { typeBinding.kind == .array }
public var arrayLengthName: String {
precondition(isArray)
return name + "Length"
}

public func toSwiftParam(label: String = "_") -> SwiftParam {
SwiftParam(label: label, name: name, `inout`: passBy.isOutput, type: typeProjection.swiftType)
SwiftParam(label: label, name: name, `inout`: passBy.isOutput, type: typeBinding.swiftType)
}
}

extension ParamProjection.PassBy {
extension ParamBinding.PassBy {
public var isInput: Bool {
switch self {
case .value, .reference(in: true, out: _, optional: _): return true
Expand Down
28 changes: 14 additions & 14 deletions Generator/Sources/ProjectionModel/Projection+params.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ extension Projection {
type: try toTypeExpression(genericTypeArgs.isEmpty ? param.type : param.type.bindGenericParams(typeArgs: genericTypeArgs)))
}

public func getParamBinding(_ param: ParamBase, genericTypeArgs: [TypeNode] = []) throws -> ParamProjection {
let passBy: ParamProjection.PassBy = switch param {
public func getParamBinding(_ param: ParamBase, genericTypeArgs: [TypeNode] = []) throws -> ParamBinding {
let passBy: ParamBinding.PassBy = switch param {
case is ReturnParam: .return(nullAsError: isNullAsErrorEligible(try param.type))
case let param as Param:
param.isByRef
Expand All @@ -25,14 +25,14 @@ extension Projection {
default: fatalError("Unexpected parameter class")
}

return ParamProjection(
return ParamBinding(
name: toParamName(param),
typeProjection: try getTypeBinding(
typeBinding: try getTypeBinding(
param.type.bindGenericParams(typeArgs: genericTypeArgs)),
passBy: passBy)
}

public func getParamBindings(method: Method, genericTypeArgs: [TypeNode], abiKind: ABIMethodKind? = nil) throws -> (params: [ParamProjection], return: ParamProjection?) {
public func getParamBindings(method: Method, genericTypeArgs: [TypeNode], abiKind: ABIMethodKind? = nil) throws -> (params: [ParamBinding], return: ParamBinding?) {
let abiKind = try abiKind ?? ABIMethodKind.forABITypeMethods(definition: method.definingType)

var paramBindings = try method.params.map { try getParamBinding($0, genericTypeArgs: genericTypeArgs) }
Expand All @@ -41,32 +41,32 @@ extension Projection {
// The last two parameters are the outer and inner objects,
// which should not be projected to Swift.
for i in paramBindings.count-2..<paramBindings.count {
let paramProjection = paramBindings[i]
let abiType = paramProjection.typeProjection.abiType
paramBindings[i] = ParamProjection(
name: paramProjection.name,
typeProjection: TypeProjection(
let paramBinding = paramBindings[i]
let abiType = paramBinding.typeBinding.abiType
paramBindings[i] = ParamBinding(
name: paramBinding.name,
typeBinding: TypeBinding(
abiType: abiType,
abiDefaultValue: .`nil`,
swiftType: abiType,
swiftDefaultValue: .`nil`,
bindingType: .void, // No projection needed
kind: .identity),
passBy: paramProjection.passBy)
passBy: paramBinding.passBy)
}
}

let returnBinding: ParamProjection?
let returnBinding: ParamBinding?
switch abiKind {
case .activationFactory, .composableFactory:
// Factory method. Preserve the ABI and return it as COMReference
guard case .bound(let objectType) = try method.returnType else {
fatalError("ABI factory methods are expected to return a bound type.")
}
let abiType = try toABIType(objectType)
returnBinding = ParamProjection(
returnBinding = ParamBinding(
name: "_result",
typeProjection: TypeProjection(
typeBinding: TypeBinding(
abiType: .unsafeMutablePointer(pointee: abiType).optional(),
abiDefaultValue: .`nil`,
swiftType: SupportModules.COM.comReference(to: abiType),
Expand Down
42 changes: 21 additions & 21 deletions Generator/Sources/ProjectionModel/Projection+types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ extension Projection {
try toTypeExpression(type, outerNullable: !isNullAsErrorEligible(type))
}

public func getTypeBinding(_ type: TypeNode) throws -> TypeProjection {
public func getTypeBinding(_ type: TypeNode) throws -> TypeBinding {
switch type {
case let .bound(type):
return try getTypeBinding(type)
Expand All @@ -83,7 +83,7 @@ extension Projection {
case let .array(of: element):
let elementBinding = try getTypeBinding(element)
let swiftType = SwiftType.array(element: elementBinding.swiftType)
return TypeProjection(
return TypeBinding(
abiType: SupportModules.COM.comArray(of: elementBinding.abiType),
abiDefaultValue: .defaultInitializer,
swiftType: swiftType,
Expand All @@ -96,7 +96,7 @@ extension Projection {
}
}

private func getTypeBinding(_ type: BoundType) throws -> TypeProjection {
private func getTypeBinding(_ type: BoundType) throws -> TypeBinding {
if let specialTypeBinding = try getSpecialTypeBinding(type) {
return specialTypeBinding
}
Expand All @@ -117,7 +117,7 @@ extension Projection {
abiType = .unsafeMutablePointer(pointee: abiType).optional()
}

return TypeProjection(
return TypeBinding(
abiType: abiType,
abiDefaultValue: type.definition.isReferenceType ? "nil" : .defaultInitializer,
swiftType: try toTypeExpression(type.asNode),
Expand All @@ -126,23 +126,23 @@ extension Projection {
kind: try isPODBinding(type.definition) ? .pod : .allocating)
}

private func getSpecialTypeBinding(_ type: BoundType) throws -> TypeProjection? {
private func getSpecialTypeBinding(_ type: BoundType) throws -> TypeBinding? {
if type.definition.namespace == "System" {
guard let typeProjection = try getCoreLibraryTypeBinding(type) else {
guard let typeBinding = try getCoreLibraryTypeBinding(type) else {
throw UnexpectedTypeError(type.description, context: "Not a valid WinRT System type.")
}
return typeProjection
return typeBinding
}
else if type.definition.namespace == "Windows.Foundation",
let typeProjection = try getWindowsFoundationTypeBinding(type) {
return typeProjection
let typeBinding = try getWindowsFoundationTypeBinding(type) {
return typeBinding
}
else {
return nil
}
}

private func getCoreLibraryTypeBinding(_ type: BoundType) throws -> TypeProjection? {
private func getCoreLibraryTypeBinding(_ type: BoundType) throws -> TypeBinding? {
guard type.definition.namespace == "System" else { return nil }

if type.definition.name == "Object" {
Expand All @@ -163,23 +163,23 @@ extension Projection {
let swiftType: SwiftType = primitiveType == .boolean ? .bool
: primitiveType == .float(double: false) ? .float
: .swift(primitiveType.name)
return TypeProjection(
return TypeBinding(
abiType: swiftType,
abiDefaultValue: primitiveType == .boolean ? .`false` : .zero,
swiftType: swiftType,
swiftDefaultValue: primitiveType == .boolean ? .`false` : .zero,
bindingType: SupportModules.WinRT.primitiveBinding(of: primitiveType),
kind: .identity)
case .char16:
return TypeProjection(
return TypeBinding(
abiType: .swift("UInt16"),
abiDefaultValue: .zero,
swiftType: SupportModules.WinRT.char16,
swiftDefaultValue: ".init(0)",
bindingType: SupportModules.WinRT.primitiveBinding(of: primitiveType),
kind: .pod)
case .guid:
return TypeProjection(
return TypeBinding(
abiType: .named(CAbi.guidName),
abiDefaultValue: .defaultInitializer,
swiftType: SupportModules.COM.guid,
Expand All @@ -197,15 +197,15 @@ extension Projection {
}
}

private func getWindowsFoundationTypeBinding(_ type: BoundType) throws -> TypeProjection? {
private func getWindowsFoundationTypeBinding(_ type: BoundType) throws -> TypeBinding? {
guard type.definition.namespace == "Windows.Foundation" else { return nil }
switch type.definition.name {
case "IReference`1":
guard case let .bound(type) = type.genericArgs[0] else { return nil }
return try getIReferenceTypeBinding(of: type)

case "EventRegistrationToken":
return TypeProjection(
return TypeBinding(
abiType: .named(CAbi.eventRegistrationTokenName),
abiDefaultValue: .defaultInitializer,
swiftType: SupportModules.WinRT.eventRegistrationToken,
Expand All @@ -214,7 +214,7 @@ extension Projection {
kind: .pod)

case "HResult":
return TypeProjection(
return TypeBinding(
abiType: .named(CAbi.hresultName),
abiDefaultValue: .zero,
swiftType: SupportModules.COM.hresult,
Expand All @@ -227,24 +227,24 @@ extension Projection {
}
}

private func getIReferenceTypeBinding(of type: BoundType) throws -> TypeProjection? {
let typeProjection = try getTypeBinding(type.asNode)
private func getIReferenceTypeBinding(of type: BoundType) throws -> TypeBinding? {
let typeBinding = try getTypeBinding(type.asNode)
let bindingType: SwiftType
if type.definition.namespace == "System",
let primitiveType = WinRTPrimitiveType(fromSystemNamespaceType: type.definition.name) {
bindingType = SupportModules.WinRT.ireferenceToOptionalBinding(of: primitiveType)
}
else if type.definition is EnumDefinition || type.definition is StructDefinition || type.definition is DelegateDefinition {
bindingType = SupportModules.WinRT.ireferenceToOptionalBinding(of: typeProjection.bindingType)
bindingType = SupportModules.WinRT.ireferenceToOptionalBinding(of: typeBinding.bindingType)
}
else {
return nil
}

return TypeProjection(
return TypeBinding(
abiType: .unsafeMutablePointer(pointee: .named(CAbi.ireferenceName)).optional(),
abiDefaultValue: .nil,
swiftType: typeProjection.swiftType.optional(),
swiftType: typeBinding.swiftType.optional(),
swiftDefaultValue: .nil,
bindingType: bindingType,
kind: .allocating)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import CodeWriters

/// Describes a type's Swift and ABI representation, and how to project between the two.
public struct TypeProjection {
public struct TypeBinding {
public enum DefaultValue: ExpressibleByStringLiteral, CustomStringConvertible {
case defaultInitializer // .init()
case expression(String)
Expand Down Expand Up @@ -57,8 +57,8 @@ public struct TypeProjection {
self.kind = kind
}

public static func numeric(_ type: SwiftType) -> TypeProjection {
TypeProjection(
public static func numeric(_ type: SwiftType) -> TypeBinding {
TypeBinding(
abiType: type,
abiDefaultValue: "0",
swiftType: type,
Expand Down
28 changes: 14 additions & 14 deletions Generator/Sources/SwiftWinRT/Writing/ABIBinding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ fileprivate func writeStructBindingExtension(
if index > 0 { output.write(",", endLine: true) }
try writeStructABIToSwiftInitializerParam(
abiValueName: "value", abiFieldName: field.name, swiftFieldName: Projection.toMemberName(field),
typeProjection: projection.getTypeBinding(field.type), to: output)
typeBinding: projection.getTypeBinding(field.type), to: output)
}
}
output.write(")", endLine: true)
Expand All @@ -176,7 +176,7 @@ fileprivate func writeStructBindingExtension(
if index > 0 { output.write(",", endLine: true) }
try writeStructSwiftToABIInitializerParam(
swiftValueName: "value", swiftFieldName: Projection.toMemberName(field), abiFieldName: field.name,
typeProjection: projection.getTypeBinding(field.type), to: output)
typeBinding: projection.getTypeBinding(field.type), to: output)
}
}
output.write(")", endLine: true)
Expand All @@ -188,9 +188,9 @@ fileprivate func writeStructBindingExtension(
visibility: .public, static: true, name: "release",
params: [.init(label: "_", name: "value", `inout`: true, type: abiType)]) { writer in
for field in fields {
let typeProjection = try projection.getTypeBinding(field.type)
if typeProjection.kind == .allocating {
writer.writeStatement("\(typeProjection.bindingType).release(&value.\(field.name))")
let typeBinding = try projection.getTypeBinding(field.type)
if typeBinding.kind == .allocating {
writer.writeStatement("\(typeBinding.bindingType).release(&value.\(field.name))")
}
}
}
Expand All @@ -200,43 +200,43 @@ fileprivate func writeStructBindingExtension(

fileprivate func writeStructABIToSwiftInitializerParam(
abiValueName: String, abiFieldName: String, swiftFieldName: String,
typeProjection: TypeProjection, to output: LineBasedTextOutputStream) throws {
typeBinding: TypeBinding, to output: LineBasedTextOutputStream) throws {
var output = output
SwiftIdentifier.write(swiftFieldName, to: &output)
output.write(": ")

if typeProjection.kind != .identity {
typeProjection.bindingType.write(to: &output)
if typeBinding.kind != .identity {
typeBinding.bindingType.write(to: &output)
output.write(".fromABI(")
}

SwiftIdentifier.write(abiValueName, to: &output)
output.write(".")
SwiftIdentifier.write(abiFieldName, to: &output)

if typeProjection.kind != .identity {
if typeBinding.kind != .identity {
output.write(")")
}
}

fileprivate func writeStructSwiftToABIInitializerParam(
swiftValueName: String, swiftFieldName: String, abiFieldName: String,
typeProjection: TypeProjection, to output: LineBasedTextOutputStream) throws {
typeBinding: TypeBinding, to output: LineBasedTextOutputStream) throws {
var output = output
SwiftIdentifier.write(abiFieldName, to: &output)
output.write(": ")

if typeProjection.kind != .identity {
if typeProjection.kind != .pod { output.write("try ") }
typeProjection.bindingType.write(to: &output)
if typeBinding.kind != .identity {
if typeBinding.kind != .pod { output.write("try ") }
typeBinding.bindingType.write(to: &output)
output.write(".toABI(")
}

SwiftIdentifier.write(swiftValueName, to: &output)
output.write(".")
SwiftIdentifier.write(swiftFieldName, to: &output)

if typeProjection.kind != .identity {
if typeBinding.kind != .identity {
output.write(")")
}
}
Expand Down
Loading

0 comments on commit 0f83c59

Please sign in to comment.