@@ -33,98 +33,125 @@ public struct HTTPClientResponse: Sendable {
3333 /// The body of this HTTP response.
3434 public var body : Body
3535
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-
5136 init (
5237 bag: Transaction ,
5338 version: HTTPVersion ,
5439 status: HTTPResponseStatus ,
5540 headers: HTTPHeaders
5641 ) {
57- self . body = Body ( bag)
5842 self . version = version
5943 self . status = status
6044 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
6158 }
6259}
6360
6461@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
6772
68- public struct AsyncIterator : AsyncIteratorProtocol {
69- private let stream : IteratorStream
73+ @inlinable init ( storage: Storage . AsyncIterator ) {
74+ self . storage = storage
75+ }
7076
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+ }
7380 }
7481
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 ( ) )
7786 }
7887 }
88+ }
7989
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 > )
8295 }
8396}
8497
8598@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 ( ) )
95108 }
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+ }
96119
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 ( )
99129 }
100130 }
101131}
102132
103133@available ( macOS 10 . 15 , iOS 13 . 0 , watchOS 6 . 0 , tvOS 13 . 0 , * )
104134extension 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+ }
113138
114- private var id : ID { ID ( self ) }
115- private let bag : Transaction
139+ @usableFromInline init ( _ storage: Storage ) {
140+ self . storage = storage
141+ }
116142
117- init ( bag : Transaction ) {
118- self . bag = bag
119- }
143+ public init ( ) {
144+ self = . stream ( EmptyCollection < ByteBuffer > ( ) . async )
145+ }
120146
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+ }
124152
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 )
128155 }
129156}
130157
0 commit comments