Skip to content

Commit

Permalink
Added methods to box Swift collections into WinRT-compatible collecti…
Browse files Browse the repository at this point in the history
…ons.
  • Loading branch information
tristanlabelle committed Apr 8, 2024
1 parent 236474b commit 929cbc4
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 1 deletion.
4 changes: 3 additions & 1 deletion Generator/Sources/ProjectionModel/SupportModules.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ extension SupportModules.WinRT {
]
internal static let windowsFoundationCollections = [
"IIterable`1",
"IIterator`1"
"IIterator`1",
"IVector`1",
"IVectorView`1"
]
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
extension Array {
public func toWinRTIVector(elementEquals: @escaping (Element, Element) -> Bool) -> ArrayVector<Element> {
ArrayVector(self, elementEquals: elementEquals)
}
}

extension Array where Element: Equatable {
public func toWinRTIVector() -> ArrayVector<Element> {
ArrayVector(self, elementEquals: ==)
}
}

/// Wraps a Swift array into a type implementing WinRT's Windows.Foundation.Collections.IVector<T>.
public class ArrayVector<T>: WinRTExport<IInspectableProjection>,
WindowsFoundationCollections_IVectorProtocol, WindowsFoundationCollections_IVectorViewProtocol {
public var array: [T]
public var elementEquals: (T, T) -> Bool

init(_ array: [T], elementEquals: @escaping (T, T) -> Bool) {
self.array = array
self.elementEquals = elementEquals
}

public func _size() throws -> UInt32 {
UInt32(array.count)
}

public func first() throws -> WindowsFoundationCollections_IIterator<T> {
SequenceIterator(array.makeIterator())
}

public func getAt(_ index: UInt32) throws -> T {
array[Int(index)]
}

public func getView() throws -> WindowsFoundationCollections_IVectorView<T> {
array.toWinRTIVectorView(elementEquals: elementEquals)
}

public func indexOf(_ value: T, _ index: inout UInt32) throws -> Bool {
if let foundIndex = array.firstIndex(where: { elementEquals($0, value) }) {
index = UInt32(foundIndex)
return true
} else {
index = 0
return false
}
}

public func setAt(_ index: UInt32, _ value: T) throws {
array[Int(index)] = value
}

public func insertAt(_ index: UInt32, _ value: T) throws {
array.insert(value, at: Int(index))
}

public func removeAt(_ index: UInt32) throws {
array.remove(at: Int(index))
}

public func append(_ value: T) throws {
array.append(value)
}

public func removeAtEnd() throws {
array.removeLast()
}

public func clear() throws {
array.removeAll()
}

public func getMany(_ startIndex: UInt32, _ items: [T]) throws -> UInt32 {
throw HResult.Error.notImpl // TODO(#31): Implement out arrays
}

public func replaceAll(_ items: [T]) throws {
array = items
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
extension Collection where Index == Int {
public func toWinRTIVectorView(elementEquals: @escaping (Element, Element) -> Bool) -> WindowsFoundationCollections_IVectorView<Element> {
CollectionVectorView(self, elementEquals: elementEquals)
}
}

extension Collection where Index == Int, Element: Equatable {
public func toWinRTIVectorView() -> WindowsFoundationCollections_IVectorView<Element> {
CollectionVectorView(self, elementEquals: ==)
}
}

fileprivate class CollectionVectorView<C: Collection>: WinRTExport<IInspectableProjection>,
WindowsFoundationCollections_IVectorViewProtocol
where C.Index == Int {
public typealias T = C.Element

public var collection: C
public var elementEquals: (T, T) -> Bool

init(_ collection: C, elementEquals: @escaping (T, T) -> Bool) {
self.collection = collection
self.elementEquals = elementEquals
}

public func _size() throws -> UInt32 {
UInt32(collection.count)
}

public func first() throws -> WindowsFoundationCollections_IIterator<T> {
SequenceIterator(collection.makeIterator())
}

public func getAt(_ index: UInt32) throws -> C.Element {
collection[Int(index)]
}

public func indexOf(_ value: C.Element, _ index: inout UInt32) throws -> Bool {
if let foundIndex = collection.firstIndex(where: { elementEquals($0, value) }) {
index = UInt32(foundIndex)
return true
} else {
index = 0
return false
}
}

public func getMany(_ startIndex: UInt32, _ items: [C.Element]) throws -> UInt32 {
throw HResult.Error.notImpl // TODO(#31): Implement out arrays
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Public types and protocols in here must be compatible with what the code generator would emit.

/// Exposes an iterator that supports simple iteration over a collection of a specified type.
public typealias WindowsFoundationCollections_IIterable<T> = any WindowsFoundationCollections_IIterableProtocol<T>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Public types and protocols in here must be compatible with what the code generator would emit.

/// Supports simple iteration over a collection.
public typealias WindowsFoundationCollections_IIterator<T> = any WindowsFoundationCollections_IIteratorProtocol<T>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Public types and protocols in here must be compatible with what the code generator would emit.

/// Represents a random-access collection of elements.
public typealias WindowsFoundationCollections_IVector<T> = any WindowsFoundationCollections_IVectorProtocol<T>

/// Represents a random-access collection of elements.
public protocol WindowsFoundationCollections_IVectorProtocol<T>: WindowsFoundationCollections_IIterableProtocol {
associatedtype T

/// Returns the item at the specified index in the vector.
/// - Parameter index: The zero-based index of the item.
/// - Returns: The item at the specified index.
func getAt(_ index: Swift.UInt32) throws -> T

/// Returns an immutable view of the vector.
/// - Returns: The view of the vector.
func getView() throws -> WindowsFoundationCollections_IVectorView<T>

/// Retrieves the index of a specified item in the vector.
/// - Parameter value: The item to find in the vector.
/// - Parameter index: If the item is found, this is the zero-based index of the item; otherwise, this parameter is 0.
/// - Returns: **true** if the item is found; otherwise, **false**.
func indexOf(_ value: T, _ index: inout Swift.UInt32) throws -> Swift.Bool

/// Sets the value at the specified index in the vector.
/// - Parameter index: The zero-based index at which to set the value.
/// - Parameter value: The item to set.
func setAt(_ index: Swift.UInt32, _ value: T) throws

/// Inserts an item at a specified index in the vector.
/// - Parameter index: The zero-based index.
/// - Parameter value: The item to insert.
func insertAt(_ index: Swift.UInt32, _ value: T) throws

/// Removes the item at the specified index in the vector.
/// - Parameter index: The zero-based index of the vector item to remove.
func removeAt(_ index: Swift.UInt32) throws

/// Appends an item to the end of the vector.
/// - Parameter value: The item to append to the vector.
func append(_ value: T) throws

/// Removes the last item from the vector.
func removeAtEnd() throws

/// Removes all items from the vector.
func clear() throws

/// Gets a collection of items from the vector beginning at the given index.
/// - Parameter startIndex: The zero-based index to start at.
/// - Parameter items: An array to copy the items into.
/// - Returns: A status code indicating the result of the operation.
func getMany(_ startIndex: Swift.UInt32, _ items: [T]) throws -> Swift.UInt32

/// Replaces all the items in the vector with the specified items.
/// - Parameter items: The collection of items to add to the vector.
func replaceAll(_ items: [T]) throws

/// Gets the number of items in the vector.
/// - Returns: The number of items in the vector.
func _size() throws -> Swift.UInt32
}

extension WindowsFoundationCollections_IVectorProtocol {
/// Gets the number of items in the vector.
/// - Returns: The number of items in the vector.
public var size: Swift.UInt32 {
try! self._size()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Public types and protocols in here must be compatible with what the code generator would emit.

/// Represents an immutable view into a vector.
public typealias WindowsFoundationCollections_IVectorView<T> = any WindowsFoundationCollections_IVectorViewProtocol<T>

/// Represents an immutable view into a vector.
public protocol WindowsFoundationCollections_IVectorViewProtocol<T>: WindowsFoundationCollections_IIterableProtocol {
associatedtype T

/// Returns the item at the specified index in the vector view.
/// - Parameter index: The zero-based index of the item.
/// - Returns: The item at the specified index.
func getAt(_ index: Swift.UInt32) throws -> T

/// Retrieves the index of a specified item in the vector view.
/// - Parameter value: The item to find in the vector view.
/// - Parameter index: If the item is found, this is the zero-based index of the item; otherwise, this parameter is 0.
/// - Returns: **true** if the item is found; otherwise, **false**.
func indexOf(_ value: T, _ index: inout Swift.UInt32) throws -> Swift.Bool

/// Gets a collection of items from the vector view beginning at the given index.
/// - Parameter startIndex: The zero-based index to start at.
/// - Parameter items: An array to copy the items into.
/// - Returns: A status code indicating the result of the operation.
func getMany(_ startIndex: Swift.UInt32, _ items: [T]) throws -> Swift.UInt32

/// Gets the number of items in the vector view.
/// - Returns: The number of items in the vector view.
func _size() throws -> Swift.UInt32
}

extension WindowsFoundationCollections_IVectorViewProtocol {
/// Gets the number of items in the vector view.
/// - Returns: The number of items in the vector view.
public var size: Swift.UInt32 {
try! self._size()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
extension Sequence {
/// Converts a Swift sequence to a WinRT IIterable.
/// - Parameter sequence: The sequence to convert.
/// - Returns: The converted IIterable.
public func toWinRTIIterable() -> WindowsFoundationCollections_IIterable<Element> {
SequenceIterable(self)
}
}

fileprivate class SequenceIterable<S: Sequence>: WinRTExport<IInspectableProjection>, WindowsFoundationCollections_IIterableProtocol {
typealias T = S.Element

private let sequence: S

init(_ sequence: S) {
self.sequence = sequence
}

func first() throws -> WindowsFoundationCollections_IIterator<S.Element> {
SequenceIterator(sequence.makeIterator())
}
}

internal class SequenceIterator<I: IteratorProtocol>: WinRTExport<IInspectableProjection>, WindowsFoundationCollections_IIteratorProtocol {
typealias T = I.Element

private var iterator: I
private var current: T?

init(_ iterator: I) {
self.iterator = iterator
self.current = self.iterator.next()
}

func _hasCurrent() throws -> Bool { current != nil }

func _current() throws -> T {
guard let current else { throw HResult.Error.illegalMethodCall }
return current
}

func moveNext() throws -> Bool {
current = iterator.next()
return current != nil
}

func getMany(_ items: [I.Element]) throws -> UInt32 {
throw HResult.Error.notImpl // TODO(#31): Implement out arrays
}
}

0 comments on commit 929cbc4

Please sign in to comment.