Skip to content

Commit

Permalink
add support for array output and by reference (#198)
Browse files Browse the repository at this point in the history
* move array methods over to specific class

* working mostly, a few test failures

* fix array testsd

* fix indentation for in and out

* fix it and ship it

* insert assignment at front

* some last fixes

* update can write

* delete debug.log...gross

* remove extra whitespace

* catch and free memory so it doesn't leak
  • Loading branch information
stevenbrix authored Jan 7, 2025
1 parent 9a4be08 commit 35e2ea1
Show file tree
Hide file tree
Showing 36 changed files with 3,483 additions and 665 deletions.
7 changes: 0 additions & 7 deletions swiftwinrt/Resources/Support/Array+FromAbi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,6 @@ extension Array {
}
}

@_spi(WinRTInternal)
extension Array {
public static func from<Bridge: AbiInterfaceBridge>(abiBridge: Bridge.Type, start: UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?, count: UInt32) -> [Element] where Element == Bridge.SwiftProjection? {
UnsafeBufferPointer(start: start, count: Int(count)).map { InterfaceWrapperBase<Bridge>.unwrapFrom(abi: ComPtr($0)) }
}
}

@_spi(WinRTInternal)
extension Array {
public static func from<Bridge: AbiBridge>(abiBridge: Bridge.Type, abi: WinRTArrayAbi<UnsafeMutablePointer<Bridge.CABI>?>) -> [Element] where Element == Bridge.SwiftProjection?, Bridge.SwiftProjection: WinRTClass {
Expand Down
88 changes: 77 additions & 11 deletions swiftwinrt/Resources/Support/Array+ToAbi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,121 @@ import Foundation

@_spi(WinRTInternal)
extension Array where Element: ToAbi {
public func toABI(_ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<Element.ABI>?) throws -> Void) throws {
public func toABI(_ withAbi: (WinRTArrayAbi<Element.ABI>) throws -> Void) throws {
let abiArray: [Element.ABI] = try map { try $0.toABI() }
try abiArray.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: Element.ABI.self)
try withAbi(UInt32(count), .init(mutating: bytesPtr))
try withAbi((count: UInt32(count), start: .init(mutating: bytesPtr)))
}
}

public func fill(abi: UnsafeMutablePointer<UnsafeMutablePointer<Element.ABI>?>?) throws {
guard let abi else { return }
abi.pointee = CoTaskMemAlloc(UInt64(MemoryLayout<Element.ABI>.size * count)).assumingMemoryBound(to: Element.ABI.self)
do {
try fill(abi: abi.pointee)
} catch {
CoTaskMemFree(abi.pointee)
throw error
}
}

public func fill(abi: UnsafeMutablePointer<Element.ABI>?) throws {
guard let abi else { return }
for (index, element) in enumerated() {
abi[index] = try element.toABI()
}
}
}

@_spi(WinRTInternal)
extension Array where Element: Numeric {
public func toABI(_ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<Element>?) throws -> Void) throws {
public func toABI(_ withAbi: (WinRTArrayAbi<Element>) throws -> Void) throws {
try withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: Element.self)
try withAbi(UInt32(count), .init(mutating: bytesPtr))
try withAbi((count: UInt32(count), start: .init(mutating: bytesPtr)))
}
}

public func fill(abi: UnsafeMutablePointer<Element>?) {
guard let abi else { return }
_ = UnsafeMutableBufferPointer(start: abi, count: count).update(from: self)
}

public func fill(abi: UnsafeMutablePointer<UnsafeMutablePointer<Element>?>?) {
guard let abi else { return }
abi.pointee = CoTaskMemAlloc(UInt64(MemoryLayout<Element>.size * count)).assumingMemoryBound(to: Element.self)
fill(abi: abi.pointee)
}
}

@_spi(WinRTInternal)
extension Array where Element: RawRepresentable, Element.RawValue: Numeric {
public func toABI(_ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<Element>?) throws -> Void) throws {
public func toABI(_ withAbi: (WinRTArrayAbi<Element>) throws -> Void) throws {
try withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: Element.self)
try withAbi(UInt32(count), .init(mutating: bytesPtr))
try withAbi((count: UInt32(count), start: .init(mutating: bytesPtr)))
}
}

public func fill(abi: UnsafeMutablePointer<Element>?) {
guard let abi else { return }
_ = UnsafeMutableBufferPointer(start: abi, count: count).update(from: self)
}

public func fill(abi: UnsafeMutablePointer<UnsafeMutablePointer<Element>?>?) {
guard let abi else { return }
abi.pointee = CoTaskMemAlloc(UInt64(MemoryLayout<Element>.size * count)).assumingMemoryBound(to: Element.self)
fill(abi: abi.pointee)
}
}

@_spi(WinRTInternal)
extension Array {
public func toABI<Bridge: AbiInterfaceBridge>(abiBridge: Bridge.Type, _ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?) throws -> Void) throws where Element == Bridge.SwiftProjection? {
public func toABI<Bridge: AbiInterfaceBridge>(abiBridge: Bridge.Type, _ withAbi: (WinRTArrayAbi<UnsafeMutablePointer<Bridge.CABI>?>) throws -> Void) throws where Element == Bridge.SwiftProjection? {
let abiWrapperArray: [InterfaceWrapperBase<Bridge>?] = map { .init($0) }
let abiArray = try abiWrapperArray.map { try $0?.toABI{ $0 } }
try abiArray.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: UnsafeMutablePointer<Bridge.CABI>?.self)
try withAbi(UInt32(count), .init(mutating: bytesPtr))
try withAbi((count: UInt32(count), start: .init(mutating: bytesPtr)))
}
}

public func fill<Bridge: AbiInterfaceBridge>(abi: UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?, abiBridge: Bridge.Type) where Element == Bridge.SwiftProjection? {
guard let abi else { return }
for (index, element) in enumerated() {
let wrapper = InterfaceWrapperBase<Bridge>(element)
wrapper?.copyTo(&abi[index])
}
}

public func fill<Bridge: AbiInterfaceBridge>(abi: UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?>?, abiBridge: Bridge.Type) where Element == Bridge.SwiftProjection? {
guard let abi else { return }
abi.pointee = CoTaskMemAlloc(UInt64(MemoryLayout<UnsafeMutablePointer<Bridge.CABI>>.size * count)).assumingMemoryBound(to: UnsafeMutablePointer<Bridge.CABI>?.self)
fill(abi: abi.pointee, abiBridge: abiBridge)
}
}

@_spi(WinRTInternal)
extension Array {
public func toABI<Bridge: AbiBridge>(abiBridge: Bridge.Type, _ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?) throws -> Void) throws where Element == Bridge.SwiftProjection?, Bridge.SwiftProjection: WinRTClass {
public func toABI<Bridge: AbiBridge>(abiBridge: Bridge.Type, _ withAbi: (WinRTArrayAbi<UnsafeMutablePointer<Bridge.CABI>?>) throws -> Void) throws where Element == Bridge.SwiftProjection?, Bridge.SwiftProjection: WinRTClass {
let abiArray: [UnsafeMutablePointer<Bridge.CABI>?] = map { RawPointer($0) }
try abiArray.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: UnsafeMutablePointer<Bridge.CABI>?.self)
try withAbi(UInt32(count), .init(mutating: bytesPtr))
try withAbi((count: UInt32(count), start: .init(mutating: bytesPtr)))
}
}

public func fill<Bridge: AbiBridge>(abi: UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?, abiBridge: Bridge.Type) where Element == Bridge.SwiftProjection?, Bridge.SwiftProjection: WinRTClass {
guard let abi else { return }
for (index, element) in enumerated() {
abi[index] = RawPointer(element)
}
}
}

public func fill<Bridge: AbiBridge>(abi: UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?>?, abiBridge: Bridge.Type) where Element == Bridge.SwiftProjection?, Bridge.SwiftProjection: WinRTClass {
guard let abi else { return }
abi.pointee = CoTaskMemAlloc(UInt64(MemoryLayout<UnsafeMutablePointer<Bridge.CABI>>.size * count)).assumingMemoryBound(to: UnsafeMutablePointer<Bridge.CABI>?.self)
fill(abi: abi.pointee, abiBridge: abiBridge)
}
}
24 changes: 24 additions & 0 deletions swiftwinrt/Resources/Support/Array+toVector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ internal class ArrayVector<T> : IVector {
func replaceAll(_ items: [T]) {
storage = items
}

func getMany(_ startIndex: UInt32, _ items: inout [T]) -> UInt32 {
let count = Swift.min(UInt32(storage.count) - startIndex, UInt32(items.count))
for i in 0..<count {
items[Int(i)] = storage[Int(startIndex + i)]
}
return count
}
}

extension ArrayVector where T: Equatable {
Expand All @@ -56,6 +64,14 @@ internal class ArrayVectorView<T> : IVectorView {
func indexOf(_ item: T, _ index: inout UInt32) -> Bool { return false }

func first() -> AnyIIterator<T>? { ArrayIterator(storage) }

func getMany(_ startIndex: UInt32, _ items: inout [T]) -> UInt32 {
let count = Swift.min(UInt32(storage.count) - startIndex, UInt32(items.count))
for i in 0..<count {
items[Int(i)] = storage[Int(startIndex + i)]
}
return count
}
}

extension ArrayVectorView where T: Equatable {
Expand All @@ -82,4 +98,12 @@ class ArrayIterator<T>: IIterator {
var hasCurrent: Bool { index < storage.count }

func queryInterface(_ iid: IID) -> IUnknownRef? { nil }

func getMany(_ items: inout [T]) -> UInt32 {
let count = Swift.min(storage.count - index, items.count)
for i in 0..<count {
items[i] = storage[index + i]
}
return UInt32(count)
}
}
1 change: 1 addition & 0 deletions swiftwinrt/abi_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ namespace swiftwinrt
#undef FindText
#undef GetClassName
#undef GetObject
#undef GetGlyphIndices
#define ENABLE_WINRT_EXPERIMENTAL_TYPES
Expand Down
Loading

0 comments on commit 35e2ea1

Please sign in to comment.