Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename (Type|Param)Projection to (Type|Param)Binding #473

Merged
merged 1 commit into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading