From 3329370f422cea3781a95cbb6015d04f8407d19b Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Wed, 1 Dec 2021 20:02:09 +0100 Subject: [PATCH 1/4] HTTPClientRequest --- .../AsyncAwait/HTTPClientRequest+Body.swift | 110 ++++++++++++++++++ .../AsyncAwait/HTTPClientRequest.swift | 34 ++++++ 2 files changed, 144 insertions(+) create mode 100644 Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Body.swift create mode 100644 Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Body.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Body.swift new file mode 100644 index 000000000..4589b0d74 --- /dev/null +++ b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Body.swift @@ -0,0 +1,110 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AsyncHTTPClient open source project +// +// Copyright (c) 2021 Apple Inc. and the AsyncHTTPClient project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +#if compiler(>=5.5) && canImport(_Concurrency) +import NIOCore + +@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +extension HTTPClientRequest { + struct Body { + internal enum Mode { + case asyncSequence(length: Int?, (ByteBufferAllocator) async throws -> ByteBuffer?) + case sequence(length: Int?, (ByteBufferAllocator) -> ByteBuffer) + case byteBuffer(ByteBuffer) + } + + var mode: Mode + + private init(_ mode: Mode) { + self.mode = mode + } + } +} + +@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +extension HTTPClientRequest.Body { + static func byteBuffer(_ byteBuffer: ByteBuffer) -> Self { + self.init(.byteBuffer(byteBuffer)) + } + + static func bytes( + length: Int? = nil, + _ bytes: Bytes + ) -> Self where Bytes: Sequence, Bytes.Element == UInt8 { + self.init(.sequence(length: length) { allocator in + if let buffer = bytes.withContiguousStorageIfAvailable({ allocator.buffer(bytes: $0) }) { + // fastpath + return buffer + } + // potentially really slow path + return allocator.buffer(bytes: bytes) + }) + } + + static func bytes( + _ bytes: Bytes + ) -> Self where Bytes: RandomAccessCollection, Bytes.Element == UInt8 { + self.init(.sequence(length: bytes.count) { allocator in + if let buffer = bytes.withContiguousStorageIfAvailable({ allocator.buffer(bytes: $0) }) { + // fastpath + return buffer + } + // potentially really slow path + return allocator.buffer(bytes: bytes) + }) + } + + /// This method should never be used and was always deprecated. + /// The whole purpose of this overload is to prevent users from providing a redundant length if `Bytes` conforms to + /// `RandomAccessCollection` because it already provide a property `count` to get the length in O(**1**). + /// - Note: `length` is ignored in favour of `bytes.count` + @available(*, deprecated, message: "no need to manually specify `length` because we automatically use `bytes.count` as the `length`") + static func bytes( + length: Int, + _ collection: Bytes + ) -> Self where Bytes: RandomAccessCollection, Bytes.Element == UInt8 { + return .bytes(collection) + } + + static func stream( + length: Int? = nil, + _ sequenceOfBytes: SequenceOfBytes + ) -> Self where SequenceOfBytes: AsyncSequence, SequenceOfBytes.Element == ByteBuffer { + var iterator = sequenceOfBytes.makeAsyncIterator() + let body = self.init(.asyncSequence(length: length) { _ -> ByteBuffer? in + try await iterator.next() + }) + return body + } + + static func stream( + length: Int? = nil, + _ bytes: Bytes + ) -> Self where Bytes: AsyncSequence, Bytes.Element == UInt8 { + var iterator = bytes.makeAsyncIterator() + let body = self.init(.asyncSequence(length: nil) { allocator -> ByteBuffer? in + var buffer = allocator.buffer(capacity: 1024) // TODO: Magic number + while buffer.writableBytes > 0, let byte = try await iterator.next() { + buffer.writeInteger(byte) + } + if buffer.readableBytes > 0 { + return buffer + } + return nil + }) + return body + } +} + +#endif diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift new file mode 100644 index 000000000..869d3704f --- /dev/null +++ b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the AsyncHTTPClient open source project +// +// Copyright (c) 2021 Apple Inc. and the AsyncHTTPClient project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +#if compiler(>=5.5) && canImport(_Concurrency) +import NIOHTTP1 + +@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +struct HTTPClientRequest { + var url: String + var method: HTTPMethod + var headers: HTTPHeaders + + var body: Body? + + init(url: String) { + self.url = url + self.method = .GET + self.headers = .init() + self.body = .none + } +} + +#endif From 8e4b2b4267029978821737c42e920dfd6b2fe4d3 Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Wed, 1 Dec 2021 20:50:06 +0100 Subject: [PATCH 2/4] move into single file --- .../AsyncAwait/HTTPClientRequest+Body.swift | 110 ------------------ .../AsyncAwait/HTTPClientRequest.swift | 93 +++++++++++++++ 2 files changed, 93 insertions(+), 110 deletions(-) delete mode 100644 Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Body.swift diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Body.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Body.swift deleted file mode 100644 index 4589b0d74..000000000 --- a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest+Body.swift +++ /dev/null @@ -1,110 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the AsyncHTTPClient open source project -// -// Copyright (c) 2021 Apple Inc. and the AsyncHTTPClient project authors -// Licensed under Apache License v2.0 -// -// See LICENSE.txt for license information -// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors -// -// SPDX-License-Identifier: Apache-2.0 -// -//===----------------------------------------------------------------------===// - -#if compiler(>=5.5) && canImport(_Concurrency) -import NIOCore - -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) -extension HTTPClientRequest { - struct Body { - internal enum Mode { - case asyncSequence(length: Int?, (ByteBufferAllocator) async throws -> ByteBuffer?) - case sequence(length: Int?, (ByteBufferAllocator) -> ByteBuffer) - case byteBuffer(ByteBuffer) - } - - var mode: Mode - - private init(_ mode: Mode) { - self.mode = mode - } - } -} - -@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) -extension HTTPClientRequest.Body { - static func byteBuffer(_ byteBuffer: ByteBuffer) -> Self { - self.init(.byteBuffer(byteBuffer)) - } - - static func bytes( - length: Int? = nil, - _ bytes: Bytes - ) -> Self where Bytes: Sequence, Bytes.Element == UInt8 { - self.init(.sequence(length: length) { allocator in - if let buffer = bytes.withContiguousStorageIfAvailable({ allocator.buffer(bytes: $0) }) { - // fastpath - return buffer - } - // potentially really slow path - return allocator.buffer(bytes: bytes) - }) - } - - static func bytes( - _ bytes: Bytes - ) -> Self where Bytes: RandomAccessCollection, Bytes.Element == UInt8 { - self.init(.sequence(length: bytes.count) { allocator in - if let buffer = bytes.withContiguousStorageIfAvailable({ allocator.buffer(bytes: $0) }) { - // fastpath - return buffer - } - // potentially really slow path - return allocator.buffer(bytes: bytes) - }) - } - - /// This method should never be used and was always deprecated. - /// The whole purpose of this overload is to prevent users from providing a redundant length if `Bytes` conforms to - /// `RandomAccessCollection` because it already provide a property `count` to get the length in O(**1**). - /// - Note: `length` is ignored in favour of `bytes.count` - @available(*, deprecated, message: "no need to manually specify `length` because we automatically use `bytes.count` as the `length`") - static func bytes( - length: Int, - _ collection: Bytes - ) -> Self where Bytes: RandomAccessCollection, Bytes.Element == UInt8 { - return .bytes(collection) - } - - static func stream( - length: Int? = nil, - _ sequenceOfBytes: SequenceOfBytes - ) -> Self where SequenceOfBytes: AsyncSequence, SequenceOfBytes.Element == ByteBuffer { - var iterator = sequenceOfBytes.makeAsyncIterator() - let body = self.init(.asyncSequence(length: length) { _ -> ByteBuffer? in - try await iterator.next() - }) - return body - } - - static func stream( - length: Int? = nil, - _ bytes: Bytes - ) -> Self where Bytes: AsyncSequence, Bytes.Element == UInt8 { - var iterator = bytes.makeAsyncIterator() - let body = self.init(.asyncSequence(length: nil) { allocator -> ByteBuffer? in - var buffer = allocator.buffer(capacity: 1024) // TODO: Magic number - while buffer.writableBytes > 0, let byte = try await iterator.next() { - buffer.writeInteger(byte) - } - if buffer.readableBytes > 0 { - return buffer - } - return nil - }) - return body - } -} - -#endif diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift index 869d3704f..5540ad8dd 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #if compiler(>=5.5) && canImport(_Concurrency) +import NIOCore import NIOHTTP1 @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) @@ -31,4 +32,96 @@ struct HTTPClientRequest { } } +@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +extension HTTPClientRequest { + struct Body { + internal enum Mode { + case asyncSequence(length: Int?, (ByteBufferAllocator) async throws -> ByteBuffer?) + case sequence(length: Int?, (ByteBufferAllocator) -> ByteBuffer) + case byteBuffer(ByteBuffer) + } + + var mode: Mode + + private init(_ mode: Mode) { + self.mode = mode + } + } +} + +@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) +extension HTTPClientRequest.Body { + static func byteBuffer(_ byteBuffer: ByteBuffer) -> Self { + self.init(.byteBuffer(byteBuffer)) + } + + static func bytes( + length: Int? = nil, + _ bytes: Bytes + ) -> Self where Bytes: Sequence, Bytes.Element == UInt8 { + self.init(.sequence(length: length) { allocator in + if let buffer = bytes.withContiguousStorageIfAvailable({ allocator.buffer(bytes: $0) }) { + // fastpath + return buffer + } + // potentially really slow path + return allocator.buffer(bytes: bytes) + }) + } + + static func bytes( + _ bytes: Bytes + ) -> Self where Bytes: RandomAccessCollection, Bytes.Element == UInt8 { + self.init(.sequence(length: bytes.count) { allocator in + if let buffer = bytes.withContiguousStorageIfAvailable({ allocator.buffer(bytes: $0) }) { + // fastpath + return buffer + } + // potentially really slow path + return allocator.buffer(bytes: bytes) + }) + } + + /// This method should never be used and was always deprecated. + /// The whole purpose of this overload is to prevent users from providing a redundant length if `Bytes` conforms to + /// `RandomAccessCollection` because it already provide a property `count` to get the length in O(**1**). + /// - Note: `length` is ignored in favour of `bytes.count` + @available(*, deprecated, message: "no need to manually specify `length` because we automatically use `bytes.count` as the `length`") + static func bytes( + length: Int, + _ collection: Bytes + ) -> Self where Bytes: RandomAccessCollection, Bytes.Element == UInt8 { + return .bytes(collection) + } + + static func stream( + length: Int? = nil, + _ sequenceOfBytes: SequenceOfBytes + ) -> Self where SequenceOfBytes: AsyncSequence, SequenceOfBytes.Element == ByteBuffer { + var iterator = sequenceOfBytes.makeAsyncIterator() + let body = self.init(.asyncSequence(length: length) { _ -> ByteBuffer? in + try await iterator.next() + }) + return body + } + + static func stream( + length: Int? = nil, + _ bytes: Bytes + ) -> Self where Bytes: AsyncSequence, Bytes.Element == UInt8 { + var iterator = bytes.makeAsyncIterator() + let body = self.init(.asyncSequence(length: nil) { allocator -> ByteBuffer? in + var buffer = allocator.buffer(capacity: 1024) // TODO: Magic number + while buffer.writableBytes > 0, let byte = try await iterator.next() { + buffer.writeInteger(byte) + } + if buffer.readableBytes > 0 { + return buffer + } + return nil + }) + return body + } +} + #endif From 85e6dc489cf9c84da32550acfaf327da68812624 Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Thu, 2 Dec 2021 10:23:34 +0100 Subject: [PATCH 3/4] fix review comments --- .../AsyncAwait/HTTPClientRequest.swift | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift index 5540ad8dd..3651c9016 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift @@ -55,10 +55,11 @@ extension HTTPClientRequest.Body { self.init(.byteBuffer(byteBuffer)) } - static func bytes( + @inlinable + static func bytes( length: Int? = nil, _ bytes: Bytes - ) -> Self where Bytes: Sequence, Bytes.Element == UInt8 { + ) -> Self where Bytes.Element == UInt8 { self.init(.sequence(length: length) { allocator in if let buffer = bytes.withContiguousStorageIfAvailable({ allocator.buffer(bytes: $0) }) { // fastpath @@ -69,9 +70,10 @@ extension HTTPClientRequest.Body { }) } - static func bytes( + @inlinable + static func bytes( _ bytes: Bytes - ) -> Self where Bytes: RandomAccessCollection, Bytes.Element == UInt8 { + ) -> Self where Bytes.Element == UInt8 { self.init(.sequence(length: bytes.count) { allocator in if let buffer = bytes.withContiguousStorageIfAvailable({ allocator.buffer(bytes: $0) }) { // fastpath @@ -87,17 +89,19 @@ extension HTTPClientRequest.Body { /// `RandomAccessCollection` because it already provide a property `count` to get the length in O(**1**). /// - Note: `length` is ignored in favour of `bytes.count` @available(*, deprecated, message: "no need to manually specify `length` because we automatically use `bytes.count` as the `length`") - static func bytes( + @inlinable + static func bytes( length: Int, _ collection: Bytes - ) -> Self where Bytes: RandomAccessCollection, Bytes.Element == UInt8 { + ) -> Self where Bytes.Element == UInt8 { return .bytes(collection) } - static func stream( + @inlinable + static func stream( length: Int? = nil, _ sequenceOfBytes: SequenceOfBytes - ) -> Self where SequenceOfBytes: AsyncSequence, SequenceOfBytes.Element == ByteBuffer { + ) -> Self where SequenceOfBytes.Element == ByteBuffer { var iterator = sequenceOfBytes.makeAsyncIterator() let body = self.init(.asyncSequence(length: length) { _ -> ByteBuffer? in try await iterator.next() @@ -105,10 +109,11 @@ extension HTTPClientRequest.Body { return body } - static func stream( + @inlinable + static func stream( length: Int? = nil, _ bytes: Bytes - ) -> Self where Bytes: AsyncSequence, Bytes.Element == UInt8 { + ) -> Self where Bytes.Element == UInt8 { var iterator = bytes.makeAsyncIterator() let body = self.init(.asyncSequence(length: nil) { allocator -> ByteBuffer? in var buffer = allocator.buffer(capacity: 1024) // TODO: Magic number From 7448dfce89697b64caab8bc55cc3d5b2a476f5cc Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Thu, 2 Dec 2021 10:36:12 +0100 Subject: [PATCH 4/4] remove overload --- .../AsyncAwait/HTTPClientRequest.swift | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift index 3651c9016..a7d40d468 100644 --- a/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift +++ b/Sources/AsyncHTTPClient/AsyncAwait/HTTPClientRequest.swift @@ -84,19 +84,6 @@ extension HTTPClientRequest.Body { }) } - /// This method should never be used and was always deprecated. - /// The whole purpose of this overload is to prevent users from providing a redundant length if `Bytes` conforms to - /// `RandomAccessCollection` because it already provide a property `count` to get the length in O(**1**). - /// - Note: `length` is ignored in favour of `bytes.count` - @available(*, deprecated, message: "no need to manually specify `length` because we automatically use `bytes.count` as the `length`") - @inlinable - static func bytes( - length: Int, - _ collection: Bytes - ) -> Self where Bytes.Element == UInt8 { - return .bytes(collection) - } - @inlinable static func stream( length: Int? = nil,