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 support for array output and by reference #198

Merged
merged 11 commits into from
Jan 7, 2025
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