Skip to content

Commit 7dfed60

Browse files
committed
Address review comments
1 parent 13e03cd commit 7dfed60

File tree

5 files changed

+113
-66
lines changed

5 files changed

+113
-66
lines changed

Sources/AsyncHTTPClient/AsyncAwait/AnyAsyncSequence.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ struct AnyAsyncSequence<Element>: Sendable, AsyncSequence {
3131

3232
@usableFromInline var makeAsyncIteratorCallback: @Sendable () -> AsyncIteratorNextCallback
3333

34-
@inlinable public init<SequenceOfBytes>(
34+
@inlinable init<SequenceOfBytes>(
3535
_ asyncSequence: SequenceOfBytes
3636
) where SequenceOfBytes: AsyncSequence & Sendable, SequenceOfBytes.Element == Element {
3737
self.makeAsyncIteratorCallback = {

Sources/AsyncHTTPClient/AsyncAwait/AsyncSequenceFromSyncSequence.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the AsyncHTTPClient open source project
44
//
5-
// Copyright (c) 2021 Apple Inc. and the AsyncHTTPClient project authors
5+
// Copyright (c) 2022 Apple Inc. and the AsyncHTTPClient project authors
66
// Licensed under Apache License v2.0
77
//
88
// See LICENSE.txt for license information
@@ -44,7 +44,7 @@ extension AsyncLazySequence.AsyncIterator: Sendable where Base.Iterator: Sendabl
4444

4545
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
4646
extension Sequence {
47-
/// Turns `self` into an `AsyncSequence` by wending each element of `self` asynchronously.
47+
/// Turns `self` into an `AsyncSequence` by vending each element of `self` asynchronously.
4848
@inlinable var async: AsyncLazySequence<Self> {
4949
.init(base: self)
5050
}

Sources/AsyncHTTPClient/AsyncAwait/HTTPClientResponse.swift

+67-15
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,16 @@ public struct HTTPClientResponse: Sendable {
4545
self.body = Body(TransactionBody(bag))
4646
}
4747

48-
@inlinable public init(){
49-
self.version = .http1_1
50-
self.status = .ok
51-
self.headers = [:]
52-
self.body = Body()
48+
@inlinable public init(
49+
version: HTTPVersion = .http1_1,
50+
status: HTTPResponseStatus = .ok,
51+
headers: HTTPHeaders = [:],
52+
body: Body = Body()
53+
) {
54+
self.version = version
55+
self.status = status
56+
self.headers = headers
57+
self.body = body
5358
}
5459
}
5560

@@ -62,7 +67,6 @@ extension HTTPClientResponse {
6267
/// are entirely synthetic and have no semantic meaning.
6368
public struct Body: AsyncSequence, Sendable {
6469
public typealias Element = ByteBuffer
65-
@usableFromInline typealias Storage = Either<TransactionBody, AnyAsyncSequence<ByteBuffer>>
6670
public struct AsyncIterator: AsyncIteratorProtocol {
6771
@usableFromInline var storage: Storage.AsyncIterator
6872

@@ -85,22 +89,70 @@ extension HTTPClientResponse {
8589

8690
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
8791
extension HTTPClientResponse.Body {
88-
@inlinable init(_ body: TransactionBody) {
89-
self.storage = .a(body)
92+
@usableFromInline enum Storage: Sendable {
93+
case transaction(SingleIteratorPrecondition<TransactionBody>)
94+
case anyAsyncSequence(AnyAsyncSequence<ByteBuffer>)
9095
}
96+
}
97+
98+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
99+
extension HTTPClientResponse.Body.Storage: AsyncSequence {
100+
@usableFromInline typealias Element = ByteBuffer
91101

92-
@inlinable public init<SequenceOfBytes>(
93-
_ sequenceOfBytes: SequenceOfBytes
94-
) where SequenceOfBytes: AsyncSequence & Sendable, SequenceOfBytes.Element == ByteBuffer {
95-
self.storage = .b(AnyAsyncSequence(sequenceOfBytes))
102+
@inlinable func makeAsyncIterator() -> AsyncIterator {
103+
switch self {
104+
case .transaction(let transaction):
105+
return .transaction(transaction.makeAsyncIterator())
106+
case .anyAsyncSequence(let anyAsyncSequence):
107+
return .anyAsyncSequence(anyAsyncSequence.makeAsyncIterator())
108+
}
109+
}
110+
}
111+
112+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
113+
extension HTTPClientResponse.Body.Storage {
114+
@usableFromInline enum AsyncIterator {
115+
case transaction(SingleIteratorPrecondition<TransactionBody>.AsyncIterator)
116+
case anyAsyncSequence(AnyAsyncSequence<ByteBuffer>.AsyncIterator)
117+
}
118+
}
119+
120+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
121+
extension HTTPClientResponse.Body.Storage.AsyncIterator: AsyncIteratorProtocol {
122+
@inlinable mutating func next() async throws -> ByteBuffer? {
123+
switch self {
124+
case .transaction(let iterator):
125+
return try await iterator.next()
126+
case .anyAsyncSequence(var iterator):
127+
defer { self = .anyAsyncSequence(iterator) }
128+
return try await iterator.next()
129+
}
130+
}
131+
}
132+
133+
134+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
135+
extension HTTPClientResponse.Body {
136+
init(_ body: TransactionBody) {
137+
self.init(.transaction(body.singleIteratorPrecondition))
138+
}
139+
140+
@usableFromInline init(_ storage: Storage) {
141+
self.storage = storage
96142
}
97143

98144
public init() {
99-
self.init(EmptyCollection().async)
145+
self = .stream(EmptyCollection<ByteBuffer>().async)
146+
}
147+
148+
@inlinable public static func stream<SequenceOfBytes>(
149+
_ sequenceOfBytes: SequenceOfBytes
150+
) -> Self where SequenceOfBytes: AsyncSequence & Sendable, SequenceOfBytes.Element == ByteBuffer {
151+
self.init(.anyAsyncSequence(AnyAsyncSequence(sequenceOfBytes.singleIteratorPrecondition)))
100152
}
101153

102-
public init(_ byteBuffer: ByteBuffer) {
103-
self.init(CollectionOfOne(byteBuffer).async)
154+
public static func bytes(_ byteBuffer: ByteBuffer) -> Self {
155+
.stream(CollectionOfOne(byteBuffer).async)
104156
}
105157
}
106158

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the AsyncHTTPClient open source project
4+
//
5+
// Copyright (c) 2022 Apple Inc. and the AsyncHTTPClient project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Atomics
16+
17+
/// Makes sure that a consumer of this `AsyncSequence`
18+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
19+
@usableFromInline struct SingleIteratorPrecondition<Base: AsyncSequence>: AsyncSequence {
20+
@usableFromInline let base: Base
21+
@usableFromInline let didCreateIterator: ManagedAtomic<Bool> = .init(false)
22+
@usableFromInline typealias Element = Base.Element
23+
@inlinable init(base: Base) {
24+
self.base = base
25+
}
26+
@inlinable func makeAsyncIterator() -> Base.AsyncIterator {
27+
precondition(
28+
self.didCreateIterator.exchange(true, ordering: .relaxed) == false
29+
)
30+
return base.makeAsyncIterator()
31+
}
32+
}
33+
34+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
35+
extension SingleIteratorPrecondition: @unchecked Sendable where Base: Sendable {}
36+
37+
38+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
39+
extension AsyncSequence {
40+
@inlinable var singleIteratorPrecondition: SingleIteratorPrecondition<Self> {
41+
.init(base: self)
42+
}
43+
}

Sources/AsyncHTTPClient/Either.swift

-48
This file was deleted.

0 commit comments

Comments
 (0)