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

Introduce WinRTPrimitiveProjection(.Int32 etc.) and implement value type boxing #86

Merged
merged 3 commits into from
Mar 25, 2024
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
10 changes: 6 additions & 4 deletions Generator/Sources/ProjectionModel/SupportModules.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,10 @@ extension SupportModules.WinRT {
public static var moduleName: String { "WindowsRuntime" }

public static var char16: SwiftType { .chain(moduleName, "Char16") }
public static var char16Projection: SwiftType { .chain(moduleName, "Char16Projection") }

public static var comIInspectableStruct: SwiftType { .chain(moduleName, "COMIInspectableStruct") }
public static var eventRegistration: SwiftType { .chain(moduleName, "EventRegistration") }
public static var eventRegistrationToken: SwiftType { .chain(moduleName, "EventRegistrationToken") }
public static var hstringProjection: SwiftType { .chain(moduleName, "HStringProjection") }
public static var iinspectable: SwiftType { .chain(moduleName, "IInspectable") }
public static var iinspectablePointer: SwiftType { .chain(moduleName, "IInspectablePointer") }
public static var iinspectableProjection: SwiftType { .chain(moduleName, "IInspectableProjection") }
Expand All @@ -75,8 +73,12 @@ extension SupportModules.WinRT {
.chain([ .init(moduleName), .init("WinRTArrayProjection", genericArgs: [type]) ])
}

public static func ireferenceProjection(of type: WinRTPrimitiveType) -> SwiftType {
.chain([ .init(moduleName), .init("WindowsFoundation_IReferenceProjection"), .init(type.name) ])
public static func winRTPrimitiveProjection(of type: WinRTPrimitiveType) -> SwiftType {
.chain([ .init(moduleName), .init("WinRTPrimitiveProjection"), .init(type.name) ])
}

public static func ireferenceUnboxingProjection(of type: WinRTPrimitiveType) -> SwiftType {
.chain([ .init(moduleName), .init("IReferenceUnboxingProjection"), .init(type.name) ])
}

public static var winRTClassLoader: SwiftType { .chain(moduleName, "WinRTClassLoader") }
Expand Down
35 changes: 15 additions & 20 deletions Generator/Sources/ProjectionModel/SwiftProjection+types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,46 +153,41 @@ extension SwiftProjection {
guard let primitiveType = WinRTPrimitiveType(fromSystemNamespaceType: type.definition.name) else { return nil }

switch primitiveType {
case .boolean:
// Identity projections
case .boolean, .integer(_), .float(_):
let swiftType = primitiveType == .boolean ? SwiftType.bool
: primitiveType == .float(double: false) ? SwiftType.float
: SwiftType.chain("Swift", primitiveType.name)
return TypeProjection(
abiType: .bool,
abiDefaultValue: .`false`,
swiftType: .bool,
swiftDefaultValue: .`false`,
projectionType: SupportModules.COM.boolProjection,
abiType: swiftType,
abiDefaultValue: primitiveType == .boolean ? .`false` : .zero,
swiftType: swiftType,
swiftDefaultValue: primitiveType == .boolean ? .`false` : .zero,
projectionType: SupportModules.WinRT.winRTPrimitiveProjection(of: primitiveType),
kind: .identity)
case .integer(.uint8): return .numeric(.uint(bits: 8))
case .integer(.int16): return .numeric(.int(bits: 16))
case .integer(.uint16): return .numeric(.uint(bits: 16))
case .integer(.int32): return .numeric(.int(bits: 32))
case .integer(.uint32): return .numeric(.uint(bits: 32))
case .integer(.int64): return .numeric(.int(bits: 64))
case .integer(.uint64): return .numeric(.uint(bits: 64))
case .float(double: false): return .numeric(.float)
case .float(double: true): return .numeric(.double)
case .char16:
return TypeProjection(
abiType: .chain("Swift", "UInt16"),
abiDefaultValue: .zero,
swiftType: SupportModules.WinRT.char16,
swiftDefaultValue: .zero,
projectionType: SupportModules.WinRT.char16Projection,
swiftDefaultValue: ".init(0)",
projectionType: SupportModules.WinRT.winRTPrimitiveProjection(of: primitiveType),
kind: .inert)
case .guid:
return TypeProjection(
abiType: .chain(abiModuleName, CAbi.guidName),
abiDefaultValue: .defaultInitializer,
swiftType: .chain("Foundation", "UUID"),
swiftDefaultValue: .defaultInitializer,
projectionType: SupportModules.COM.guidProjection,
projectionType: SupportModules.WinRT.winRTPrimitiveProjection(of: primitiveType),
kind: .inert)
case .string:
return .init(
abiType: .optional(wrapped: .chain(abiModuleName, CAbi.hstringName)),
abiDefaultValue: .nil,
swiftType: .string,
swiftDefaultValue: .emptyString,
projectionType: SupportModules.WinRT.hstringProjection,
projectionType: SupportModules.WinRT.winRTPrimitiveProjection(of: primitiveType),
kind: .allocating)
}
}
Expand Down Expand Up @@ -236,7 +231,7 @@ extension SwiftProjection {
abiDefaultValue: .nil,
swiftType: .optional(wrapped: typeProjection.swiftType),
swiftDefaultValue: .nil,
projectionType: SupportModules.WinRT.ireferenceProjection(of: primitiveType),
projectionType: SupportModules.WinRT.ireferenceUnboxingProjection(of: primitiveType),
kind: .allocating)
}

Expand Down
11 changes: 0 additions & 11 deletions Support/Sources/WindowsRuntime/Char16.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import COM

/// Represents the WinRT Char16 (aka System.Char) type, a UTF-16 code unit.
/// Supports type-based disambiguation from UInt16 values.
public struct Char16: Hashable {
Expand All @@ -9,12 +7,3 @@ public struct Char16: Hashable {
self.codeUnit = codeUnit
}
}

public enum Char16Projection: ABIInertProjection {
public typealias ABIType = UInt16
public typealias SwiftType = Char16

public static var abiDefaultValue: UInt16 { 0 }
public static func toSwift(_ value: UInt16) -> Char16 { Char16(value) }
public static func toABI(_ value: Char16) -> UInt16 { value.codeUnit }
}
22 changes: 0 additions & 22 deletions Support/Sources/WindowsRuntime/HStringProjection.swift

This file was deleted.

4 changes: 2 additions & 2 deletions Support/Sources/WindowsRuntime/IActivationFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import COM
import WindowsRuntime_ABI

public func getActivationFactory<COMInterface>(activatableId: String, id: COMInterfaceID) throws -> COM.COMReference<COMInterface> {
var activatableId = try HStringProjection.toABI(activatableId)
defer { HStringProjection.release(&activatableId) }
var activatableId = try WinRTPrimitiveProjection.String.toABI(activatableId)
defer { WinRTPrimitiveProjection.String.release(&activatableId) }

var iid = GUIDProjection.toABI(id)
var rawPointer: UnsafeMutableRawPointer?
Expand Down
2 changes: 1 addition & 1 deletion Support/Sources/WindowsRuntime/IInspectable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ extension COMInterop where Interface: /* @retroactive */ COMIInspectableStruct {
public func getRuntimeClassName() throws -> String {
var runtimeClassName: WindowsRuntime_ABI.SWRT_HString?
try WinRTError.throwIfFailed(inspectable.pointee.lpVtbl.pointee.GetRuntimeClassName(inspectable, &runtimeClassName))
return HStringProjection.toSwift(consuming: &runtimeClassName)
return WinRTPrimitiveProjection.String.toSwift(consuming: &runtimeClassName)
}

public func getTrustLevel() throws -> TrustLevel {
Expand Down
104 changes: 45 additions & 59 deletions Support/Sources/WindowsRuntime/IInspectableBoxing.swift
Original file line number Diff line number Diff line change
@@ -1,79 +1,65 @@
import WindowsRuntime_ABI
import struct Foundation.UUID

/// Provides helper methods to box and unbox primitive types, value types and delegates to IInspectable.
public enum IInspectableBoxing {
private static func toSwift(_ inspectable: consuming COMReference<SWRT_IInspectable>) -> IInspectable {
IInspectableProjection.toSwift(inspectable)
public func box(_ value: Bool) throws -> IInspectable { try WinRTPrimitiveProjection.Boolean.box(value) }
public func box(_ value: UInt8) throws -> IInspectable { try WinRTPrimitiveProjection.UInt8.box(value) }
public func box(_ value: Int16) throws -> IInspectable { try WinRTPrimitiveProjection.Int16.box(value) }
public func box(_ value: UInt16) throws -> IInspectable { try WinRTPrimitiveProjection.UInt16.box(value) }
public func box(_ value: Int32) throws -> IInspectable { try WinRTPrimitiveProjection.Int32.box(value) }
public func box(_ value: UInt32) throws -> IInspectable { try WinRTPrimitiveProjection.UInt32.box(value) }
public func box(_ value: Int64) throws -> IInspectable { try WinRTPrimitiveProjection.Int64.box(value) }
public func box(_ value: UInt64) throws -> IInspectable { try WinRTPrimitiveProjection.UInt64.box(value) }
public func box(_ value: Float) throws -> IInspectable { try WinRTPrimitiveProjection.Single.box(value) }
public func box(_ value: Double) throws -> IInspectable { try WinRTPrimitiveProjection.Double.box(value) }
public func box(_ value: Char16) throws -> IInspectable { try WinRTPrimitiveProjection.Char16.box(value) }
public func box(_ value: String) throws -> IInspectable { try WinRTPrimitiveProjection.String.box(value) }
public func box(_ value: UUID) throws -> IInspectable { try WinRTPrimitiveProjection.Guid.box(value) }
public func box<BoxableValue: WinRTBoxableProjection>(_ value: BoxableValue) throws -> IInspectable
where BoxableValue.SwiftValue == BoxableValue {
try BoxableValue.box(value)
}
}

// Primitives
extension IInspectableBoxing {
public static func uint8(_ value: UInt8) throws -> IInspectable { try toSwift(PropertyValueStatics.createUInt8(value)) }
public static func int16(_ value: Int16) throws -> IInspectable { try toSwift(PropertyValueStatics.createInt16(value)) }
public static func uint16(_ value: UInt16) throws -> IInspectable { try toSwift(PropertyValueStatics.createUInt16(value)) }
public static func int32(_ value: Int32) throws -> IInspectable { try toSwift(PropertyValueStatics.createInt32(value)) }
public static func uint32(_ value: UInt32) throws -> IInspectable { try toSwift(PropertyValueStatics.createUInt32(value)) }
public static func int64(_ value: Int64) throws -> IInspectable { try toSwift(PropertyValueStatics.createInt64(value)) }
public static func uint64(_ value: UInt64) throws -> IInspectable { try toSwift(PropertyValueStatics.createUInt64(value)) }
public static func single(_ value: Float) throws -> IInspectable { try toSwift(PropertyValueStatics.createSingle(value)) }
public static func double(_ value: Double) throws -> IInspectable { try toSwift(PropertyValueStatics.createDouble(value)) }
public static func char16(_ value: Char16) throws -> IInspectable { try toSwift(PropertyValueStatics.createChar16(value)) }
public static func string(_ value: String) throws -> IInspectable { try toSwift(PropertyValueStatics.createString(value)) }
public static func guid(_ value: UUID) throws -> IInspectable { try toSwift(PropertyValueStatics.createGuid(value)) }

private static func unboxPrimitive<ABIValue>(_ inspectable: IInspectable, ireferenceID: COMInterfaceID) -> ABIValue? {
do {
let ireference = try inspectable._queryInterface(ireferenceID).reinterpret(to: SWRT_WindowsFoundation_IReference.self)
return try withUnsafeTemporaryAllocation(of: ABIValue.self, capacity: 1) {
let valuePointer = $0.baseAddress
try WinRTError.throwIfFailed(ireference.pointer.pointee.lpVtbl.pointee.get_Value(ireference.pointer, valuePointer))
return valuePointer!.pointee
}
}
catch {
return nil
}
public static func unboxBoolean(_ inspectable: IInspectable) -> Bool? {
WinRTPrimitiveProjection.Boolean.unbox(inspectable)
}

public static func asUInt8(_ inspectable: IInspectable) -> UInt8? {
unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.uint8)
public static func unboxUInt8(_ inspectable: IInspectable) -> UInt8? {
WinRTPrimitiveProjection.UInt8.unbox(inspectable)
}
public static func unboxInt16(_ inspectable: IInspectable) -> Int16? {
WinRTPrimitiveProjection.Int16.unbox(inspectable)
}
public static func asInt16(_ inspectable: IInspectable) -> Int16? {
unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.int16)
public static func unboxUInt16(_ inspectable: IInspectable) -> UInt16? {
WinRTPrimitiveProjection.UInt16.unbox(inspectable)
}
public static func asUInt16(_ inspectable: IInspectable) -> UInt16? {
unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.uint16)
public static func unboxInt32(_ inspectable: IInspectable) -> Int32? {
WinRTPrimitiveProjection.Int32.unbox(inspectable)
}
public static func asInt32(_ inspectable: IInspectable) -> Int32? {
unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.int32)
public static func unboxUInt32(_ inspectable: IInspectable) -> UInt32? {
WinRTPrimitiveProjection.UInt32.unbox(inspectable)
}
public static func asUInt32(_ inspectable: IInspectable) -> UInt32? {
unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.uint32)
public static func unboxInt64(_ inspectable: IInspectable) -> Int64? {
WinRTPrimitiveProjection.Int64.unbox(inspectable)
}
public static func asInt64(_ inspectable: IInspectable) -> Int64? {
unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.int64)
public static func unboxUInt64(_ inspectable: IInspectable) -> UInt64? {
WinRTPrimitiveProjection.UInt64.unbox(inspectable)
}
public static func asUInt64(_ inspectable: IInspectable) -> UInt64? {
unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.uint64)
public static func unboxSingle(_ inspectable: IInspectable) -> Float? {
WinRTPrimitiveProjection.Single.unbox(inspectable)
}
public static func asSingle(_ inspectable: IInspectable) -> Float? {
unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.single)
public static func unboxDouble(_ inspectable: IInspectable) -> Double? {
WinRTPrimitiveProjection.Double.unbox(inspectable)
}
public static func asDouble(_ inspectable: IInspectable) -> Double? {
unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.double)
public static func unboxChar16(_ inspectable: IInspectable) -> Char16? {
WinRTPrimitiveProjection.Char16.unbox(inspectable)
}
public static func asChar16(_ inspectable: IInspectable) -> Char16? {
guard let codeUnit: UInt16 = unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.char16) else { return nil }
return Char16Projection.toSwift(codeUnit)
public static func unboxString(_ inspectable: IInspectable) -> String? {
WinRTPrimitiveProjection.String.unbox(inspectable)
}
public static func asString(_ inspectable: IInspectable) -> String? {
guard var hstring: SWRT_HString? = unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.string) else { return nil }
return HStringProjection.toSwift(consuming: &hstring)
public static func unboxGuid(_ inspectable: IInspectable) -> UUID? {
WinRTPrimitiveProjection.Guid.unbox(inspectable)
}
public static func asGuid(_ inspectable: IInspectable) -> UUID? {
guard let guid: SWRT_Guid = unboxPrimitive(inspectable, ireferenceID: PropertyValueStatics.IReferenceIDs.guid) else { return nil }
return COM.GUIDProjection.toSwift(guid)
public static func unbox<Projection: WinRTBoxableProjection>(_ inspectable: IInspectable, projection: Projection.Type) -> Projection.SwiftValue? {
Projection.unbox(inspectable)
}
}
41 changes: 41 additions & 0 deletions Support/Sources/WindowsRuntime/IReferenceUnboxingProjection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import COM
import WindowsRuntime_ABI
import struct Foundation.UUID

public enum IReferenceUnboxingProjection {
public typealias Boolean = Of<WinRTPrimitiveProjection.Boolean>
public typealias UInt8 = Of<WinRTPrimitiveProjection.UInt8>
public typealias Int16 = Of<WinRTPrimitiveProjection.Int16>
public typealias UInt16 = Of<WinRTPrimitiveProjection.UInt16>
public typealias Int32 = Of<WinRTPrimitiveProjection.Int32>
public typealias UInt32 = Of<WinRTPrimitiveProjection.UInt32>
public typealias Int64 = Of<WinRTPrimitiveProjection.Int64>
public typealias UInt64 = Of<WinRTPrimitiveProjection.UInt64>
public typealias Single = Of<WinRTPrimitiveProjection.Single>
public typealias Double = Of<WinRTPrimitiveProjection.Double>
public typealias Char16 = Of<WinRTPrimitiveProjection.Char16>
public typealias String = Of<WinRTPrimitiveProjection.String>
public typealias Guid = Of<WinRTPrimitiveProjection.Guid>

public enum Of<Projection: WinRTBoxableProjection>: WinRTProjection {
public typealias SwiftObject = Projection.SwiftValue
public typealias COMInterface = WindowsRuntime_ABI.SWRT_WindowsFoundation_IReference
public typealias COMVirtualTable = WindowsRuntime_ABI.SWRT_WindowsFoundation_IReferenceVTable

public static var runtimeClassName: Swift.String { fatalError("Not implemented: \(#function)") }
public static var interfaceID: COMInterfaceID { Projection.ireferenceID }

public static func toSwift(_ reference: consuming COMReference<COMInterface>) -> SwiftObject {
var abiValue = Projection.abiDefaultValue
withUnsafeMutablePointer(to: &abiValue) { abiValuePointer in
_ = try! HResult.throwIfFailed(reference.pointer.pointee.lpVtbl.pointee.get_Value(
reference.pointer, abiValuePointer))
}
return Projection.toSwift(consuming: &abiValue)
}

public static func toCOM(_ value: SwiftObject) throws -> COMReference<COMInterface> {
try Projection.box(value)._queryInterface(interfaceID).reinterpret()
}
}
}
Loading
Loading