13
13
//===----------------------------------------------------------------------===//
14
14
15
15
#if compiler(>=5.5) && canImport(_Concurrency)
16
+ import NIOCore
16
17
import NIOHTTP1
17
18
18
19
@available ( macOS 12 . 0 , iOS 15 . 0 , watchOS 8 . 0 , tvOS 15 . 0 , * )
@@ -31,4 +32,96 @@ struct HTTPClientRequest {
31
32
}
32
33
}
33
34
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
+
34
127
#endif
0 commit comments