-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* new comptr stuff is building! * all building...but crashing * all gucci * add comments describing ComPtrs design * remove IUnknown2 * undo unnecessary add * fixing ref count of comptr * Revert "undo unnecessary add" This reverts commit cbabceb. * working for weak ref, but this might not actually work * fix event subscriptions * fix ref count for aggregated objects * cache interfaces as lazy vars on the classes * properly hide _inner * Update swiftwinrt/Resources/Support/ComPtr.swift Co-authored-by: Jeff <[email protected]> * Update swiftwinrt/Resources/Support/ComPtr.swift Co-authored-by: Jeff <[email protected]> * return identity and don't use ComObject since classes require strong ref to identity * fix build break * use spi and some other cleanup so i don't need dubious _getRetainCount call * add extra test cases * add deinitializers to ensure proper cleanup * Update swiftwinrt/Resources/Support/Aggregation.swift Co-authored-by: Jeff <[email protected]> --------- Co-authored-by: Jeff <[email protected]>
- Loading branch information
1 parent
5bd2bfa
commit fe63cb9
Showing
43 changed files
with
1,862 additions
and
1,539 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
// Copyright © 2023 The Browser Company | ||
// SPDX-License-Identifier: BSD-3 | ||
import C_BINDINGS_MODULE | ||
|
||
// ComPtr is a smart pointer for COM interfaces. It holds on to the underlying pointer | ||
|
||
// and the semantics of it are meant to mirror that of the ComPtr class in WRL. The | ||
// design of ComPtr and ComPtrs.intialize is that there should be no use of UnsafeMutablePointer | ||
// anywhere else in the code base. The only place where UnsafeMutablePointer should be used is | ||
|
||
// where it's required at the ABI boundary. | ||
public class ComPtr<CInterface> { | ||
fileprivate var pUnk: UnsafeMutablePointer<CInterface>? | ||
|
||
public init(_ ptr: UnsafeMutablePointer<CInterface>) { | ||
self.pUnk = ptr | ||
asIUnknown { | ||
_ = $0.pointee.lpVtbl.pointee.AddRef($0) | ||
} | ||
} | ||
|
||
public convenience init?(_ ptr: UnsafeMutablePointer<CInterface>?) { | ||
guard let ptr else { return nil } | ||
self.init(ptr) | ||
} | ||
|
||
fileprivate init?(takingOwnership ptr: UnsafeMutablePointer<CInterface>?) { | ||
guard let ptr else { return nil } | ||
self.pUnk = ptr | ||
} | ||
|
||
// Release ownership of the underlying pointer and return it. This is | ||
// useful when assigning to an out parameter and avoids an extra Add/Ref | ||
// release call. | ||
public func detach() -> UnsafeMutableRawPointer? { | ||
let result = pUnk | ||
pUnk = nil | ||
return UnsafeMutableRawPointer(result) | ||
} | ||
|
||
public func get() -> UnsafeMutablePointer<CInterface> { | ||
guard let pUnk else { preconditionFailure("get() called on nil pointer") } | ||
return pUnk | ||
} | ||
|
||
deinit { | ||
release() | ||
} | ||
|
||
private func release() { | ||
guard pUnk != nil else { return } | ||
asIUnknown { | ||
_ = $0.pointee.lpVtbl.pointee.Release($0) | ||
} | ||
} | ||
|
||
func asIUnknown<ResultType>(_ body: (UnsafeMutablePointer<C_IUnknown>) throws -> ResultType) rethrows -> ResultType { | ||
guard let pUnk else { preconditionFailure("asIUnknown called on nil pointer") } | ||
return try pUnk.withMemoryRebound(to: C_IUnknown.self, capacity: 1) { try body($0) } | ||
} | ||
} | ||
|
||
public extension ComPtr { | ||
func queryInterface<Interface: IUnknown>() throws -> Interface { | ||
let ptr = try self.asIUnknown { pUnk in | ||
var iid = Interface.IID | ||
return try ComPtrs.initialize(to: C_IUnknown.self) { result in | ||
try CHECKED(pUnk.pointee.lpVtbl.pointee.QueryInterface(pUnk, &iid, &result)) | ||
} | ||
} | ||
return .init(ptr!) | ||
} | ||
} | ||
|
||
// ComPtrs properly initializes pointers who have ownership of the underlying raw pointers. This is used at the ABI boundary layer, for example: | ||
// let (return1, return2) = try ComPtrs.initialize { return1Abi, return2Abi in | ||
// try CHECKED(pThis.pointee.lpVtbl.pointee.Method(pThis, &return1Abi, &return2Abi)) | ||
// } | ||
public struct ComPtrs { | ||
// Note: The single initialization methods still return a tuple for ease of code generation | ||
public static func initialize<I>(to: I.Type, _ body: (inout UnsafeMutableRawPointer?) throws -> ()) rethrows -> (ComPtr<I>?) { | ||
var ptrRaw: UnsafeMutableRawPointer? | ||
try body(&ptrRaw) | ||
return (ComPtr(takingOwnership: ptrRaw?.assumingMemoryBound(to: I.self))) | ||
} | ||
|
||
public static func initialize<I>(_ body: (inout UnsafeMutablePointer<I>?) throws -> ()) rethrows -> (ComPtr<I>?) { | ||
var ptr: UnsafeMutablePointer<I>? | ||
try body(&ptr) | ||
return (ComPtr(takingOwnership: ptr)) | ||
} | ||
|
||
public static func initialize<I1, I2>(_ body: (inout UnsafeMutablePointer<I1>?, inout UnsafeMutablePointer<I2>?) throws -> ()) rethrows -> (ComPtr<I1>?, ComPtr<I2>?) { | ||
var ptr1: UnsafeMutablePointer<I1>? | ||
var ptr2: UnsafeMutablePointer<I2>? | ||
try body(&ptr1, &ptr2) | ||
return (ComPtr(takingOwnership: ptr1), ComPtr(takingOwnership: ptr2)) | ||
} | ||
|
||
public static func initialize<I1, I2, I3>(_ body: (inout UnsafeMutablePointer<I1>?, inout UnsafeMutablePointer<I2>?, inout UnsafeMutablePointer<I3>?) throws -> ()) rethrows -> (ComPtr<I1>?, ComPtr<I2>?, ComPtr<I3>?) { | ||
var ptr1: UnsafeMutablePointer<I1>? | ||
var ptr2: UnsafeMutablePointer<I2>? | ||
var ptr3: UnsafeMutablePointer<I3>? | ||
try body(&ptr1, &ptr2, &ptr3) | ||
return (ComPtr(takingOwnership: ptr1), ComPtr(takingOwnership: ptr2), ComPtr(takingOwnership: ptr3)) | ||
} | ||
|
||
public static func initialize<I1, I2, I3, I4>(_ body: (inout UnsafeMutablePointer<I1>?, inout UnsafeMutablePointer<I2>?, inout UnsafeMutablePointer<I3>?, inout UnsafeMutablePointer<I4>?) throws -> ()) rethrows -> (ComPtr<I1>?, ComPtr<I2>?, ComPtr<I3>?, ComPtr<I4>?) { | ||
var ptr1: UnsafeMutablePointer<I1>? | ||
var ptr2: UnsafeMutablePointer<I2>? | ||
var ptr3: UnsafeMutablePointer<I3>? | ||
var ptr4: UnsafeMutablePointer<I4>? | ||
try body(&ptr1, &ptr2, &ptr3, &ptr4) | ||
return (ComPtr(takingOwnership: ptr1), ComPtr(takingOwnership: ptr2), ComPtr(takingOwnership: ptr3), ComPtr(takingOwnership: ptr4)) | ||
} | ||
|
||
public static func initialize<I1, I2, I3, I4, I5>(_ body: (inout UnsafeMutablePointer<I1>?, inout UnsafeMutablePointer<I2>?, inout UnsafeMutablePointer<I3>?, inout UnsafeMutablePointer<I4>?, inout UnsafeMutablePointer<I5>?) throws -> ()) rethrows -> (ComPtr<I1>?, ComPtr<I2>?, ComPtr<I3>?, ComPtr<I4>?, ComPtr<I5>?) { | ||
var ptr1: UnsafeMutablePointer<I1>? | ||
var ptr2: UnsafeMutablePointer<I2>? | ||
var ptr3: UnsafeMutablePointer<I3>? | ||
var ptr4: UnsafeMutablePointer<I4>? | ||
var ptr5: UnsafeMutablePointer<I5>? | ||
try body(&ptr1, &ptr2, &ptr3, &ptr4, &ptr5) | ||
return (ComPtr(takingOwnership: ptr1), ComPtr(takingOwnership: ptr2), ComPtr(takingOwnership: ptr3), ComPtr(takingOwnership: ptr4), ComPtr(takingOwnership: ptr5)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.