@@ -33,98 +33,125 @@ public struct HTTPClientResponse: Sendable {
33
33
/// The body of this HTTP response.
34
34
public var body : Body
35
35
36
- /// A representation of the response body for an HTTP response.
37
- ///
38
- /// The body is streamed as an `AsyncSequence` of `ByteBuffer`, where each `ByteBuffer` contains
39
- /// an arbitrarily large chunk of data. The boundaries between `ByteBuffer` objects in the sequence
40
- /// are entirely synthetic and have no semantic meaning.
41
- public struct Body : Sendable {
42
- private let bag : Transaction
43
- private let reference : ResponseRef
44
-
45
- fileprivate init ( _ transaction: Transaction ) {
46
- self . bag = transaction
47
- self . reference = ResponseRef ( transaction: transaction)
48
- }
49
- }
50
-
51
36
init (
52
37
bag: Transaction ,
53
38
version: HTTPVersion ,
54
39
status: HTTPResponseStatus ,
55
40
headers: HTTPHeaders
56
41
) {
57
- self . body = Body ( bag)
58
42
self . version = version
59
43
self . status = status
60
44
self . headers = headers
45
+ self . body = Body ( TransactionBody ( bag) )
46
+ }
47
+
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
61
58
}
62
59
}
63
60
64
61
@available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
65
- extension HTTPClientResponse . Body : AsyncSequence {
66
- public typealias Element = AsyncIterator . Element
62
+ extension HTTPClientResponse {
63
+ /// A representation of the response body for an HTTP response.
64
+ ///
65
+ /// The body is streamed as an `AsyncSequence` of `ByteBuffer`, where each `ByteBuffer` contains
66
+ /// an arbitrarily large chunk of data. The boundaries between `ByteBuffer` objects in the sequence
67
+ /// are entirely synthetic and have no semantic meaning.
68
+ public struct Body : AsyncSequence , Sendable {
69
+ public typealias Element = ByteBuffer
70
+ public struct AsyncIterator : AsyncIteratorProtocol {
71
+ @usableFromInline var storage : Storage . AsyncIterator
67
72
68
- public struct AsyncIterator : AsyncIteratorProtocol {
69
- private let stream : IteratorStream
73
+ @inlinable init ( storage: Storage . AsyncIterator ) {
74
+ self . storage = storage
75
+ }
70
76
71
- fileprivate init ( stream: IteratorStream ) {
72
- self . stream = stream
77
+ @inlinable public mutating func next( ) async throws -> ByteBuffer ? {
78
+ try await self . storage. next ( )
79
+ }
73
80
}
74
81
75
- public mutating func next( ) async throws -> ByteBuffer ? {
76
- try await self . stream. next ( )
82
+ @usableFromInline var storage : Storage
83
+
84
+ @inlinable public func makeAsyncIterator( ) -> AsyncIterator {
85
+ . init( storage: self . storage. makeAsyncIterator ( ) )
77
86
}
78
87
}
88
+ }
79
89
80
- public func makeAsyncIterator( ) -> AsyncIterator {
81
- AsyncIterator ( stream: IteratorStream ( bag: self . bag) )
90
+ @available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
91
+ extension HTTPClientResponse . Body {
92
+ @usableFromInline enum Storage : Sendable {
93
+ case transaction( TransactionBody )
94
+ case anyAsyncSequence( AnyAsyncSequence < ByteBuffer > )
82
95
}
83
96
}
84
97
85
98
@available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
86
- extension HTTPClientResponse . Body {
87
- /// The purpose of this object is to inform the transaction about the response body being deinitialized.
88
- /// If the users has not called `makeAsyncIterator` on the body, before it is deinited, the http
89
- /// request needs to be cancelled.
90
- fileprivate final class ResponseRef : Sendable {
91
- private let transaction : Transaction
92
-
93
- init ( transaction : Transaction ) {
94
- self . transaction = transaction
99
+ extension HTTPClientResponse . Body . Storage : AsyncSequence {
100
+ @ usableFromInline typealias Element = ByteBuffer
101
+
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 ( ) )
95
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( TransactionBody . AsyncIterator )
116
+ case anyAsyncSequence( AnyAsyncSequence < ByteBuffer > . AsyncIterator )
117
+ }
118
+ }
96
119
97
- deinit {
98
- self . transaction. responseBodyDeinited ( )
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 ( )
99
129
}
100
130
}
101
131
}
102
132
103
133
@available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
104
134
extension HTTPClientResponse . Body {
105
- internal class IteratorStream {
106
- struct ID : Hashable {
107
- private let objectID : ObjectIdentifier
108
-
109
- init ( _ object: IteratorStream ) {
110
- self . objectID = ObjectIdentifier ( object)
111
- }
112
- }
135
+ init ( _ body: TransactionBody ) {
136
+ self . init ( . transaction( body) )
137
+ }
113
138
114
- private var id : ID { ID ( self ) }
115
- private let bag : Transaction
139
+ @usableFromInline init ( _ storage: Storage ) {
140
+ self . storage = storage
141
+ }
116
142
117
- init ( bag : Transaction ) {
118
- self . bag = bag
119
- }
143
+ public init ( ) {
144
+ self = . stream ( EmptyCollection < ByteBuffer > ( ) . async )
145
+ }
120
146
121
- deinit {
122
- self . bag. responseBodyIteratorDeinited ( streamID: self . id)
123
- }
147
+ @inlinable public static func stream< SequenceOfBytes> (
148
+ _ sequenceOfBytes: SequenceOfBytes
149
+ ) -> Self where SequenceOfBytes: AsyncSequence & Sendable , SequenceOfBytes. Element == ByteBuffer {
150
+ self . init ( . anyAsyncSequence( AnyAsyncSequence ( sequenceOfBytes. singleIteratorPrecondition) ) )
151
+ }
124
152
125
- func next( ) async throws -> ByteBuffer ? {
126
- try await self . bag. nextResponsePart ( streamID: self . id)
127
- }
153
+ public static func bytes( _ byteBuffer: ByteBuffer ) -> Self {
154
+ . stream( CollectionOfOne ( byteBuffer) . async )
128
155
}
129
156
}
130
157
0 commit comments