Skip to content

Commit 1f7cd0d

Browse files
authored
[Refactor] Remove ConcreteAsyncSequence (#38)
### Motivation We don't need ConcreteAsyncSequence anymore, it used to be necessary before ConfigUpdatesAsyncSequence existed, but not any more. ### Modifications Remove ConcreteAsyncSequence, internal type. ### Result Simplified code. ### Test Plan Verified tests pass on 6.2 and 6.1 locally.
1 parent c8af26e commit 1f7cd0d

File tree

7 files changed

+12
-107
lines changed

7 files changed

+12
-107
lines changed

Sources/Configuration/ConfigReader+internalHelpers.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,8 @@ extension ConfigReader {
639639
) async throws -> Return {
640640
let absoluteKey = keyPrefix.appending(key)
641641
return try await provider.watchValue(forKey: absoluteKey, type: type) { updates in
642-
let mappedUpdates = ConcreteAsyncSequence(updates)
642+
let mappedUpdates =
643+
updates
643644
.map { updateTuple in
644645
let (providerResults, value) = mergingIsSecret(
645646
isSecret,
@@ -715,7 +716,8 @@ extension ConfigReader {
715716
) async throws -> Return {
716717
let absoluteKey = keyPrefix.appending(key)
717718
return try await provider.watchValue(forKey: absoluteKey, type: type) { updates in
718-
let mappedUpdates = ConcreteAsyncSequence(updates)
719+
let mappedUpdates =
720+
updates
719721
.map { updateTuple in
720722
let (providerResults, value) = mergingIsSecret(
721723
isSecret,
@@ -790,7 +792,8 @@ extension ConfigReader {
790792
) async throws -> Return {
791793
let absoluteKey = keyPrefix.appending(key)
792794
return try await provider.watchValue(forKey: absoluteKey, type: type) { updates in
793-
let mappedUpdates = ConcreteAsyncSequence(updates)
795+
let mappedUpdates =
796+
updates
794797
.mapThrowing { updateTuple in
795798
let (providerResults, value) = mergingIsSecret(
796799
isSecret,

Sources/Configuration/ConfigSnapshotReader.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ extension ConfigReader {
363363
try await provider.watchSnapshot { updates in
364364
try await updatesHandler(
365365
ConfigUpdatesAsyncSequence(
366-
ConcreteAsyncSequence(updates)
366+
updates
367367
.map { multiSnapshot in
368368
ConfigSnapshotReader(
369369
keyPrefix: keyPrefix,

Sources/Configuration/MultiProvider.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ extension MultiProvider {
205205
updatesHandler: { updateArrays in
206206
try await body(
207207
ConfigUpdatesAsyncSequence(
208-
ConcreteAsyncSequence(updateArrays)
208+
updateArrays
209209
.map { array in
210210
MultiSnapshot(snapshots: array)
211211
}
@@ -302,7 +302,7 @@ extension MultiProvider {
302302
updatesHandler: { updateArrays in
303303
try await updatesHandler(
304304
ConfigUpdatesAsyncSequence(
305-
ConcreteAsyncSequence(updateArrays)
305+
updateArrays
306306
.map { array in
307307
var results: [AccessEvent.ProviderResult] = []
308308
for (providerIndex, lookupResult) in array.enumerated() {

Sources/Configuration/Providers/Wrappers/KeyMappingProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ extension KeyMappingProvider: ConfigProvider {
121121
try await upstream.watchSnapshot { sequence in
122122
try await updatesHandler(
123123
ConfigUpdatesAsyncSequence(
124-
ConcreteAsyncSequence(sequence)
124+
sequence
125125
.map { snapshot in
126126
MappedKeySnapshot(mapKey: self.mapKey, upstream: self.upstream.snapshot())
127127
}

Sources/Configuration/Utilities/AsyncSequences.swift

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -55,71 +55,6 @@ extension ConfigUpdatesAsyncSequence: AsyncSequence {
5555
}
5656
}
5757

58-
/// A concrete async sequence that wraps an existential async sequence.
59-
///
60-
/// This type provides a concrete implementation of `AsyncSequence` that wraps
61-
/// an existential `any AsyncSequence`. It serves as a workaround for limitations
62-
/// in Swift's type system where certain operations like `map` and other sequence
63-
/// transformations don't work directly with existential async sequences.
64-
///
65-
/// ## Purpose
66-
///
67-
/// The Swift standard library's async sequence operations require concrete types
68-
/// to function properly. When working with `any AsyncSequence`, these operations
69-
/// are not available. This wrapper provides a concrete type that enables the use
70-
/// of standard async sequence operations.
71-
///
72-
/// ## Usage
73-
///
74-
/// ```swift
75-
/// let existentialSequence: any AsyncSequence<Int, Never> = someAsyncSequence
76-
/// let concreteSequence = ConcreteAsyncSequence(existentialSequence)
77-
///
78-
/// // Now you can use standard async sequence operations
79-
/// let mappedSequence = concreteSequence.map { $0 * 2 }
80-
/// ```
81-
package struct ConcreteAsyncSequence<Element: Sendable, Failure: Error> {
82-
83-
/// The upstream async sequence that this concrete sequence wraps.
84-
///
85-
/// This property holds the async sequence that provides the actual elements.
86-
/// All operations on this concrete sequence are delegated to this upstream sequence.
87-
var upstream: any AsyncSequence<Element, Failure>
88-
89-
/// Creates a new concrete async sequence wrapping the provided existential sequence.
90-
///
91-
/// - Parameter upstream: The async sequence to wrap.
92-
package init(_ upstream: any AsyncSequence<Element, Failure>) {
93-
self.upstream = upstream
94-
}
95-
}
96-
97-
extension ConcreteAsyncSequence: AsyncSequence {
98-
99-
/// An async iterator that wraps an existential async iterator.
100-
///
101-
/// This iterator provides the concrete implementation for iterating over
102-
/// the wrapped existential async sequence. It delegates all operations
103-
/// to the upstream iterator while maintaining type safety.
104-
package struct Iterator: AsyncIteratorProtocol {
105-
106-
/// The upstream async iterator that provides the actual iteration logic.
107-
var upstream: any AsyncIteratorProtocol<Element, Failure>
108-
109-
// swift-format-ignore: AllPublicDeclarationsHaveDocumentation
110-
package mutating func next(
111-
isolation actor: isolated (any Actor)?
112-
) async throws(Failure) -> Element? {
113-
try await upstream.next(isolation: actor)
114-
}
115-
}
116-
117-
// swift-format-ignore: AllPublicDeclarationsHaveDocumentation
118-
package func makeAsyncIterator() -> Iterator {
119-
Iterator(upstream: upstream.makeAsyncIterator())
120-
}
121-
}
122-
12358
// MARK: - AsyncSequence extensions
12459

12560
extension AsyncSequence where Failure == Never {

Tests/ConfigurationTests/AsyncSequencesTests.swift

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -57,39 +57,6 @@ struct AsyncSequencesTests {
5757
#expect(results == [1, 2])
5858
}
5959

60-
// MARK: - ConcreteAsyncSequence tests
61-
62-
@Test func concreteAsyncSequenceWrapsExistentialSequence() async throws {
63-
let values = [1, 2, 3, 4, 5]
64-
let concreteSequence = ConcreteAsyncSequence(values.async)
65-
let results = await concreteSequence.collect()
66-
#expect(results == values)
67-
}
68-
69-
@Test func concreteAsyncSequenceWithEmptySequence() async throws {
70-
let concreteSequence = ConcreteAsyncSequence(([] as [Int]).async)
71-
let results = await concreteSequence.collect()
72-
#expect(results.isEmpty)
73-
}
74-
75-
@Test func concreteAsyncSequencePropagatesErrors() async throws {
76-
let throwingSequence = AsyncThrowingStream<Int, any Error> { continuation in
77-
continuation.yield(1)
78-
continuation.yield(2)
79-
continuation.finish(throwing: TestError.upstreamFailed)
80-
}
81-
let concreteSequence = ConcreteAsyncSequence(throwingSequence)
82-
83-
var results: [Int] = []
84-
let error = await #expect(throws: TestError.self) {
85-
for try await value in concreteSequence {
86-
results.append(value)
87-
}
88-
}
89-
#expect(error == .upstreamFailed)
90-
#expect(results == [1, 2])
91-
}
92-
9360
// MARK: - mapThrowing Tests
9461

9562
@Test func mapThrowingSuccessfulTransformation() async throws {

Tests/ConfigurationTests/MultiProviderTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ struct MultiProviderTests {
9595
try await multiProvider.watchValue(forKey: key, type: type) { updates in
9696
try await handler(
9797
ConfigUpdatesAsyncSequence(
98-
ConcreteAsyncSequence(updates)
98+
updates
9999
.map { update in
100100
update.1.map { .init(encodedKey: "<not tested>", value: $0) }
101101
}
@@ -116,7 +116,7 @@ struct MultiProviderTests {
116116
try await multiProvider.watchSnapshot { updates in
117117
try await updatesHandler(
118118
ConfigUpdatesAsyncSequence(
119-
ConcreteAsyncSequence(updates).map { $0 }
119+
updates.map { $0 }
120120
)
121121
)
122122
}

0 commit comments

Comments
 (0)