Skip to content

Commit

Permalink
feat: add AnyAsyncThrowingSequece, to differentiate from regular one
Browse files Browse the repository at this point in the history
This makes things easier when dealing with infinite sequences (like
values from a Combine Publisher)
  • Loading branch information
AmadeusK525 committed Jun 23, 2023
1 parent 9fee844 commit 36cad8e
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 5 deletions.
50 changes: 45 additions & 5 deletions Sources/AnyAsyncSequence/AnyAsyncSequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,63 @@ import Foundation

/// A type erased `AsyncSequence`
///
/// This type allows you to create APIs that return an `AsyncSequence` that allows consumers to iterate over the sequence, without exposing the sequence's underlyin type.
/// Typically, you wouldn't actually initialize this type yourself, but instead create one using the `.eraseToAnyAsyncSequence()` operator also provided with this package.
/// This type allows you to create APIs that return an `AsyncSequence` that allows consumers to iterate over the
/// sequence, without exposing the sequence's underlying type.
/// Typically, you wouldn't actually initialize this type yourself, but instead create one using the
/// `.eraseToAnyAsyncSequence()` operator also provided with this package.
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public struct AnyAsyncSequence<Element>: AsyncSequence {

// MARK: - Initializers

/// Create an `AnyAsyncSequence` from an `AsyncSequence` conforming type
/// - Parameter sequence: The `AnySequence` type you wish to erase
public init<T: AsyncSequence>(_ sequence: T) where T.Element == Element {
makeAsyncIteratorClosure = { AnyAsyncIterator(sequence.makeAsyncIterator()) }
}

// MARK: - API
public struct AnyAsyncIterator: AsyncIteratorProtocol {
private let nextClosure: () async -> Element?

public init<T: AsyncIteratorProtocol>(_ iterator: T) where T.Element == Element {
var iterator = iterator
nextClosure = { try? await iterator.next() }
}

public func next() async -> Element? {
await nextClosure()
}
}

// MARK: - AsyncSequence
public typealias Element = Element

public typealias AsyncIterator = AnyAsyncIterator

public func makeAsyncIterator() -> AsyncIterator {
AnyAsyncIterator(makeAsyncIteratorClosure())
}

private let makeAsyncIteratorClosure: () -> AsyncIterator
}

/// A type erased `AsyncThrowingSequence`
///
/// This type allows you to create APIs that return an `AsyncThrowingSequence` that allows consumers to iterate over the
/// sequence, without exposing the sequence's underlying type.
/// Typically, you wouldn't actually initialize this type yourself, but instead create one using the
/// `.eraseToAnyAsyncThrowingSequence()` operator also provided with this package.
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public struct AnyAsyncThrowingSequence<Element>: AsyncSequence {

// MARK: - Initializers
/// Create an `AnyAsyncSequence` from an `AsyncSequence` conforming type
/// - Parameter sequence: The `AnySequence` type you wish to erase
public init<T: AsyncSequence>(_ sequence: T) where T.Element == Element {
makeAsyncIteratorClosure = { AnyAsyncIterator(sequence.makeAsyncIterator()) }
}

// MARK: - API
public struct AnyAsyncIterator: AsyncIteratorProtocol {
private let nextClosure: () async throws -> Element?

Expand All @@ -56,7 +98,6 @@ public struct AnyAsyncSequence<Element>: AsyncSequence {
}

// MARK: - AsyncSequence

public typealias Element = Element

public typealias AsyncIterator = AnyAsyncIterator
Expand All @@ -66,5 +107,4 @@ public struct AnyAsyncSequence<Element>: AsyncSequence {
}

private let makeAsyncIteratorClosure: () -> AsyncIterator

}
5 changes: 5 additions & 0 deletions Sources/AnyAsyncSequence/AsyncSequence+AnySequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ public extension AsyncSequence {
AnyAsyncSequence(self)
}

/// Create a type erased version of this sequence
/// - Returns: The sequence, wrapped in an `AnyAsyncThrowingSequence`
func eraseToAnyAsyncThrowingSequence() -> AnyAsyncThrowingSequence<Element> where {
AnyAsyncThrowingSequence(self)
}
}

0 comments on commit 36cad8e

Please sign in to comment.