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

Add a more class documentation comments #251

Merged
merged 1 commit into from
Aug 31, 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
8 changes: 4 additions & 4 deletions Support/Sources/COM/ABIProjection/ABIProjection.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/// A type that manages the projection between the Swift and ABI representation of a type of values.
/// A type that manages projecting the ABI representation of a value into Swift and back.
public protocol ABIProjection {
/// The type for the Swift representation of values.
associatedtype SwiftValue

// The type for the ABI representation of values.
associatedtype ABIValue

/// The type for the Swift representation of values.
associatedtype SwiftValue

/// A default ABI value that can be used to initialize variables
/// and does not imply any resource allocation (release is a no-op).
static var abiDefaultValue: ABIValue { get }
Expand Down
9 changes: 5 additions & 4 deletions Support/Sources/COM/ABIProjection/BoolProjection.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/// Projects the C(++) bool type to Swift's Bool type.
public enum BoolProjection: ABIInertProjection {
public typealias ABIValue = CBool
public typealias SwiftValue = Bool
public typealias ABIValue = Bool

public static var abiDefaultValue: Bool { false }
public static func toSwift(_ value: Bool) -> Bool { value }
public static func toABI(_ value: Bool) -> Bool { value }
public static var abiDefaultValue: CBool { false }
public static func toSwift(_ value: CBool) -> Bool { value }
public static func toABI(_ value: Bool) -> CBool { value }
}
3 changes: 2 additions & 1 deletion Support/Sources/COM/ABIProjection/NumericProjection.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/// Projects a C numeric type into the corresponding Swift numeric type.
public enum NumericProjection<Value: Numeric>: ABIInertProjection {
public typealias SwiftValue = Value
public typealias ABIValue = Value
public typealias SwiftValue = Value

public static var abiDefaultValue: ABIValue { Value.zero }
public static func toSwift(_ value: Value) -> Value { value }
Expand Down
3 changes: 2 additions & 1 deletion Support/Sources/COM/ABIProjection/WideCharProjection.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/// Projects a C(++) wchar_t type into its Swift equivalent, a UTF16 code unit.
public enum WideCharProjection: ABIInertProjection {
public typealias SwiftValue = Unicode.UTF16.CodeUnit
public typealias ABIValue = UInt16
public typealias SwiftValue = Unicode.UTF16.CodeUnit

public static var abiDefaultValue: ABIValue { 0 }
public static func toSwift(_ value: UInt16) -> Unicode.UTF16.CodeUnit { value }
Expand Down
3 changes: 3 additions & 0 deletions Support/Sources/COM/BStrProjection.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import COM_ABI

/// Projects a C BSTR to a Swift Optional<String>.
/// Null and empty BSTRs are supposed to be treated the same,
/// but they have different representations, which we preserve into Swift.
public enum BStrProjection: ABIProjection {
public typealias SwiftValue = String?
public typealias ABIValue = COM_ABI.SWRT_BStr?
Expand Down
1 change: 1 addition & 0 deletions Support/Sources/COM/COMError.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/// Protocol for errors which result from a COM error HRESULT.
public protocol COMError: Error {
var hresult: HResult { get }
}
2 changes: 2 additions & 0 deletions Support/Sources/COM/COMExportBase.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// Provides derived classes with a COM-compatible representation,
/// such that they can be passed to C(++) APIs accepting COM interfaces.
/// Convenience base class for COMPrimaryExport and COMSecondaryExport.
open class COMExportBase<Projection: COMTwoWayProjection>: IUnknownProtocol {
private var comEmbedding: COMEmbedding
Expand Down
4 changes: 3 additions & 1 deletion Support/Sources/COM/COMPrimaryExport.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/// Base for classes that implement and provide identity for COM interfaces.
/// Base for Swift classes that implement one or more COM interfaces and owns the COM object identity,
/// meaning that they own the object returned when using QueryInterface for IUnknown.
/// The generic Projection parameter determines the virtual table of the identity object.
open class COMPrimaryExport<Projection: COMTwoWayProjection>: COMExportBase<Projection> {
open class var implements: [COMImplements] { [] }
open class var implementIAgileObject: Bool { true }
Expand Down
2 changes: 1 addition & 1 deletion Support/Sources/COM/COMReference.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import COM_ABI

/// Holds a strong reference to a COM object, like a C++ smart pointer.
/// Holds a strong reference to a COM object, releasing it when deinitialized, like a C++ smart pointer.
public struct COMReference<ABIStruct>: ~Copyable {
public var pointer: UnsafeMutablePointer<ABIStruct>

Expand Down
3 changes: 2 additions & 1 deletion Support/Sources/COM/COMTwoWayProjection.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import COM_ABI

/// Protocol for strongly-typed two-way COM interface projections into and from Swift.
/// Protocol for COM interfaces projected into Swift both for consuming COM objects
/// and for implementing the interface from Swift.
public protocol COMTwoWayProjection: COMProjection {
static var virtualTablePointer: UnsafeRawPointer { get }
}
Expand Down
1 change: 1 addition & 0 deletions Support/Sources/COM/FreeThreadedMarshal.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import COM_ABI

/// Provides an implementation of IMarshal based on the COM free-threaded marshaler.
internal class FreeThreadedMarshal: COMSecondaryExport<FreeThreadedMarshalProjection> {
private let marshaler: COMReference<SWRT_IMarshal>

Expand Down
1 change: 1 addition & 0 deletions Support/Sources/COM/HResult.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import COM_ABI

/// Represents a COM HRESULT value in Swift.
public struct HResult: Hashable, Codable, CustomStringConvertible, Sendable {
public typealias Value = Int32
public typealias UnsignedValue = UInt32
Expand Down
5 changes: 3 additions & 2 deletions Support/Sources/COM/IAgileObject.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import COM_ABI

/// Projection for the IAgileObject interface.
/// This is a marker interface which we automatically implement for all COM projections,
/// Projection for the IAgileObject COM interface, which marks an object as supporting agile marshaling.
/// IAgileObject is a marker interface with no methods over IUnknown's, so it does not need its own virtual table.
/// This means we can piggyback on the IUnknown virtual table to transparently implement IAgileObject,
/// so we don't need to expose a protocol type for it or a two-way projection.
public enum IAgileObjectProjection: COMProjection {
public typealias SwiftObject = IUnknown // Avoid introducing an interface for IAgileObject since it is a marker interface.
Expand Down
15 changes: 14 additions & 1 deletion Support/Sources/COM/IUnknown.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import COM_ABI

/// Represents an arbitrary COM object in Swift.
public typealias IUnknown = any IUnknownProtocol

/// Base protocol for the COM IUnknown interface in Swift.
/// Provides QueryInterface but leaves out AddRef/Release to be handled by the projection.
public protocol IUnknownProtocol: AnyObject {
/// Gets an ABI-level reference to the COM interface implementing a given interface ID,
/// or throws a COMError with E_NOINTERFACE.
///
/// Note: We can't implement a stronger contract using a COMProjection generic type here
/// because it supports implementations of QueryInterface calls coming from COM,
/// which do not have the static type of the interface to be retrieved.
func _queryInterface(_ id: COMInterfaceID) throws -> IUnknownReference
}

Expand All @@ -15,14 +25,17 @@ extension IUnknownProtocol {
try _queryInterface(Projection.interfaceID)
}

/// Queries this object for an additional COM interface described by the given projection.
/// On failure, throws a COMError with an HResult of E_NOINTERFACE.
public func queryInterface<Projection: COMProjection>(_: Projection.Type) throws -> Projection.SwiftObject {
Projection.toSwift(try self._queryInterface(Projection.self))
}
}

/// Projects C(++) IUnknown-based COM objects into Swift.
public enum IUnknownProjection: COMTwoWayProjection {
public typealias SwiftObject = IUnknown
public typealias ABIStruct = COM_ABI.SWRT_IUnknown
public typealias SwiftObject = IUnknown

public static var interfaceID: COMInterfaceID { uuidof(ABIStruct.self) }
public static var virtualTablePointer: UnsafeRawPointer { .init(withUnsafePointer(to: &virtualTable) { $0 }) }
Expand Down
26 changes: 25 additions & 1 deletion Support/Sources/COM/NullResult.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
// Error thrown when a COM or WinRT projection returns a null pointer.
/// Error thrown when a COM or WinRT projection returns a null pointer.
///
/// - Remarks:
/// The WinRT type system implies that all values of reference types can be `null`,
/// although in practice APIs will seldom return `null` values with successful `HRESULT`.
///
/// If returned reference types are exposed as `Optional<T>` in Swift,
/// it forces consumers of APIs to handle errors in two ways:
/// 1. With the `try` keyword for errors thrown due to failure HRESULTs.
/// 2. With Optional-unwrapping logic for `null` values.
/// Moreover, it means that code needs to explicitly unwrap the `Optional<T>` even
/// for APIs known to not return `null`, adding boilerplate and confusion as to
/// whether a real possible error is being handled or not.
///
/// `NullResult` allows the projection to generate non-nullable return types
/// while turning `null` return values into Swift errors thrown and handled the same way as HRESULTs.
/// It is transparent in the typical case of APIs not returning `null`, but incurs
/// additional syntax when `null` values must be handled.
///
/// The other alternative would be generate return types as implicitly unwrapped optionals,
/// which allows comparisons to `nil` and chaining with `.`, but have the disadvantage
/// of introducing implicit `fatalError`'s, of decaying into a standard optional when stored,
/// and of still requiring different failure handling as HRESULTs.
public struct NullResult: Error {
/// Unwraps a nullable value, throwing a `NullResult` if it is null.
public static func unwrap<Value>(_ value: Value?) throws -> Value {
guard let value else { throw NullResult() }
return value
}

/// Converts any thrown `NullResult` error into a null value Optional.
public static func `catch`<Value>(_ block: @autoclosure () throws -> Value) rethrows -> Value? {
do { return try block() }
catch is NullResult { return nil }
Expand Down
6 changes: 4 additions & 2 deletions Support/Sources/WindowsRuntime/AsyncAwaiter.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// Supports converting an async callback pattern into a form compatible with Swift's await.
/// Used to support `IAsyncAction.get`/`IAsyncOperation.get`.
public actor AsyncAwaiter {
private enum State {
case unsignaled
Expand All @@ -9,7 +11,7 @@ public actor AsyncAwaiter {

public init() {}

/// Block until the signal() has been called.
/// Block until `signal()` has been called.
public func wait() async {
switch state {
case .signaled: return
Expand All @@ -19,7 +21,7 @@ public actor AsyncAwaiter {
}
}

/// Unblocks any current or future wait() calls.
/// Unblocks any current or future `wait()` calls.
public func signal() async {
switch state {
case .unsignaled: state = .signaled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ import SWRT_WindowsFoundation

public enum WindowsFoundation_IReferenceProjection<TProjection: BoxableProjection>: InterfaceProjection {
public typealias SwiftObject = WindowsFoundation_IReference<TProjection.SwiftValue>

// Our ABI-level IReference<T> definition is nongeneric.
// We can do this because the pointer in get_Value(T*) has the same ABI representation for all T's.
// This allows us to avoid generating ABI code and projections for each IReference<T>,
// and hence centralize the logic for dealing with this type in the support module.
public typealias ABIStruct = SWRT_WindowsFoundation_IReference

public static var typeName: String { fatalError("Windows.Foundation.IReference`1<\(TProjection.typeName)>") }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import SWRT_WindowsFoundation

public enum WindowsFoundation_IReferenceArrayProjection<TProjection: BoxableProjection>: InterfaceProjection {
public typealias SwiftObject = WindowsFoundation_IReferenceArray<TProjection.SwiftValue>

// Our ABI-level IReferenceArray<T> definition is nongeneric, see IReference<T> for why.
public typealias ABIStruct = SWRT_WindowsFoundation_IReferenceArray

public static var typeName: String { fatalError("Windows.Foundation.IReferenceArray`1<\(TProjection.typeName)>") }
Expand Down
2 changes: 2 additions & 0 deletions Support/Sources/WindowsRuntime/PropertyValueStatics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import COM
import WindowsRuntime_ABI
import SWRT_WindowsFoundation

/// Exposes static factory methods from `Windows.Foundation.PropertyValue`,
/// which are used to box primitive types and known `Windows.Foundation` structs to `IReference<T>`/`IInspectable`.
internal enum PropertyValueStatics {
private static let iid = COMInterfaceID(0x629BDBC8, 0xD932, 0x4FF4, 0x96B9, 0x8D96C5C1E858)
private static var lazyReference: COM.COMReference<SWRT_WindowsFoundation_IPropertyValueStatics>.Optional = .none
Expand Down
1 change: 1 addition & 0 deletions Support/Sources/WindowsRuntime/winrtIdentical.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import COM

/// Determines whether two WinRT references are implemented by the same underlying object.
public func winrtIdentical(_ lhs: IInspectable, _ rhs: IInspectable) -> Bool {
comIdentical(lhs, rhs)
}
Loading