1313//===----------------------------------------------------------------------===//
1414
1515#if compiler(>=5.5) && canImport(_Concurrency)
16+ import NIOCore
1617import NIOHTTP1
1718
1819@available ( macOS 12 . 0 , iOS 15 . 0 , watchOS 8 . 0 , tvOS 15 . 0 , * )
@@ -31,4 +32,96 @@ struct HTTPClientRequest {
3132 }
3233}
3334
35+ @available ( macOS 12 . 0 , iOS 15 . 0 , watchOS 8 . 0 , tvOS 15 . 0 , * )
36+ extension HTTPClientRequest {
37+ struct Body {
38+ internal enum Mode {
39+ case asyncSequence( length: Int ? , ( ByteBufferAllocator ) async throws -> ByteBuffer ? )
40+ case sequence( length: Int ? , ( ByteBufferAllocator ) -> ByteBuffer )
41+ case byteBuffer( ByteBuffer )
42+ }
43+
44+ var mode : Mode
45+
46+ private init ( _ mode: Mode ) {
47+ self . mode = mode
48+ }
49+ }
50+ }
51+
52+ @available ( macOS 12 . 0 , iOS 15 . 0 , watchOS 8 . 0 , tvOS 15 . 0 , * )
53+ extension HTTPClientRequest . Body {
54+ static func byteBuffer( _ byteBuffer: ByteBuffer ) -> Self {
55+ self . init ( . byteBuffer( byteBuffer) )
56+ }
57+
58+ static func bytes< Bytes> (
59+ length: Int ? = nil ,
60+ _ bytes: Bytes
61+ ) -> Self where Bytes: Sequence , Bytes. Element == UInt8 {
62+ self . init ( . sequence( length: length) { allocator in
63+ if let buffer = bytes. withContiguousStorageIfAvailable ( { allocator. buffer ( bytes: $0) } ) {
64+ // fastpath
65+ return buffer
66+ }
67+ // potentially really slow path
68+ return allocator. buffer ( bytes: bytes)
69+ } )
70+ }
71+
72+ static func bytes< Bytes> (
73+ _ bytes: Bytes
74+ ) -> Self where Bytes: RandomAccessCollection , Bytes. Element == UInt8 {
75+ self . init ( . sequence( length: bytes. count) { allocator in
76+ if let buffer = bytes. withContiguousStorageIfAvailable ( { allocator. buffer ( bytes: $0) } ) {
77+ // fastpath
78+ return buffer
79+ }
80+ // potentially really slow path
81+ return allocator. buffer ( bytes: bytes)
82+ } )
83+ }
84+
85+ /// This method should never be used and was always deprecated.
86+ /// The whole purpose of this overload is to prevent users from providing a redundant length if `Bytes` conforms to
87+ /// `RandomAccessCollection` because it already provide a property `count` to get the length in O(**1**).
88+ /// - Note: `length` is ignored in favour of `bytes.count`
89+ @available ( * , deprecated, message: " no need to manually specify `length` because we automatically use `bytes.count` as the `length` " )
90+ static func bytes< Bytes> (
91+ length: Int ,
92+ _ collection: Bytes
93+ ) -> Self where Bytes: RandomAccessCollection , Bytes. Element == UInt8 {
94+ return . bytes( collection)
95+ }
96+
97+ static func stream< SequenceOfBytes> (
98+ length: Int ? = nil ,
99+ _ sequenceOfBytes: SequenceOfBytes
100+ ) -> Self where SequenceOfBytes: AsyncSequence , SequenceOfBytes. Element == ByteBuffer {
101+ var iterator = sequenceOfBytes. makeAsyncIterator ( )
102+ let body = self . init ( . asyncSequence( length: length) { _ -> ByteBuffer ? in
103+ try await iterator. next ( )
104+ } )
105+ return body
106+ }
107+
108+ static func stream< Bytes> (
109+ length: Int ? = nil ,
110+ _ bytes: Bytes
111+ ) -> Self where Bytes: AsyncSequence , Bytes. Element == UInt8 {
112+ var iterator = bytes. makeAsyncIterator ( )
113+ let body = self . init ( . asyncSequence( length: nil ) { allocator -> ByteBuffer ? in
114+ var buffer = allocator. buffer ( capacity: 1024 ) // TODO: Magic number
115+ while buffer. writableBytes > 0 , let byte = try await iterator. next ( ) {
116+ buffer. writeInteger ( byte)
117+ }
118+ if buffer. readableBytes > 0 {
119+ return buffer
120+ }
121+ return nil
122+ } )
123+ return body
124+ }
125+ }
126+
34127#endif
0 commit comments