Adopt swift-format (#2794)

* Apply formatting

* Apply no block comments rule

* Apply OmitExplicitReturns

* Apple OnlyOneTrailingClosureArgument

* Apply NoAssignmentInExpressions

* Fix up DontRepeatTypeInStaticProperties lint errors

* Apply `OrderedImports`

* Apply `ReplaceForEachWithForLoop`

* format file

* Enable the formatting pipeline

* Adopt `AmbiguousTrailingClosureOverload`

* Fix license header

* Fix format check

* Fix `EndOfLineComment`

* Fix CI

* Adapt CI script to check if changes when running formatting

* Separate lint and format into to steps

* Fix format

* Adopt `UseEarlyExits`

* Revert "Adopt `UseEarlyExits`"

This reverts commit d1ac5bbe12.
This commit is contained in:
Franz Busch
2024-07-19 11:48:17 +02:00
committed by GitHub
parent 980bd3e630
commit c9756e1083
374 changed files with 23992 additions and 14890 deletions
-1
View File
@@ -10,7 +10,6 @@ jobs:
uses: ./.github/workflows/pull_request_soundness.yml
with:
license_header_check_project_name: "SwiftNIO"
format_check_enabled: false
call-pull-request-unit-tests-workflow:
name: Unit tests
+9 -2
View File
@@ -123,5 +123,12 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run format check
run: swift format lint --parallel --recursive --strict
- name: Mark the workspace as safe
# https://github.com/actions/checkout/issues/766
run: git config --global --add safe.directory ${GITHUB_WORKSPACE}
- name: Run format lint check
run: swift format lint --strict --recursive --parallel .
- name: Run format and check for modified files
run: |
swift format format --parallel --recursive --in-place .
git diff-index --quiet HEAD
+62
View File
@@ -0,0 +1,62 @@
{
"version" : 1,
"indentation" : {
"spaces" : 4
},
"tabWidth" : 4,
"fileScopedDeclarationPrivacy" : {
"accessLevel" : "private"
},
"spacesAroundRangeFormationOperators" : false,
"indentConditionalCompilationBlocks" : false,
"indentSwitchCaseLabels" : false,
"lineBreakAroundMultilineExpressionChainComponents" : false,
"lineBreakBeforeControlFlowKeywords" : false,
"lineBreakBeforeEachArgument" : true,
"lineBreakBeforeEachGenericRequirement" : true,
"lineLength" : 120,
"maximumBlankLines" : 1,
"respectsExistingLineBreaks" : true,
"prioritizeKeepingFunctionOutputTogether" : true,
"rules" : {
"AllPublicDeclarationsHaveDocumentation" : false,
"AlwaysUseLiteralForEmptyCollectionInit" : false,
"AlwaysUseLowerCamelCase" : false,
"AmbiguousTrailingClosureOverload" : true,
"BeginDocumentationCommentWithOneLineSummary" : false,
"DoNotUseSemicolons" : true,
"DontRepeatTypeInStaticProperties" : true,
"FileScopedDeclarationPrivacy" : true,
"FullyIndirectEnum" : true,
"GroupNumericLiterals" : true,
"IdentifiersMustBeASCII" : true,
"NeverForceUnwrap" : false,
"NeverUseForceTry" : false,
"NeverUseImplicitlyUnwrappedOptionals" : false,
"NoAccessLevelOnExtensionDeclaration" : true,
"NoAssignmentInExpressions" : true,
"NoBlockComments" : true,
"NoCasesWithOnlyFallthrough" : true,
"NoEmptyTrailingClosureParentheses" : true,
"NoLabelsInCasePatterns" : true,
"NoLeadingUnderscores" : false,
"NoParensAroundConditions" : true,
"NoVoidReturnOnFunctionSignature" : true,
"OmitExplicitReturns" : true,
"OneCasePerLine" : true,
"OneVariableDeclarationPerLine" : true,
"OnlyOneTrailingClosureArgument" : true,
"OrderedImports" : true,
"ReplaceForEachWithForLoop" : true,
"ReturnVoidInsteadOfEmptyTuple" : true,
"UseEarlyExits" : false,
"UseExplicitNilCheckInConditions" : false,
"UseLetInEveryBoundCaseVariable" : false,
"UseShorthandTypeNames" : true,
"UseSingleLinePropertyGetter" : false,
"UseSynthesizedInitializer" : false,
"UseTripleSlashForDocumentationComments" : true,
"UseWhereClausesInForLoops" : false,
"ValidateDocumentationComments" : false
}
}
@@ -18,7 +18,7 @@ import NIOEmbedded
let benchmarks = {
let defaultMetrics: [BenchmarkMetric] = [
.mallocCountTotal,
.mallocCountTotal
]
Benchmark(
@@ -28,7 +28,7 @@ let benchmarks = {
// Elide the cost of the 'EmbeddedChannel'. It's only used for its pipeline.
var channels: [EmbeddedChannel] = []
channels.reserveCapacity(benchmark.scaledIterations.count)
for _ in 0 ..< benchmark.scaledIterations.count {
for _ in 0..<benchmark.scaledIterations.count {
channels.append(EmbeddedChannel())
}
@@ -19,7 +19,7 @@ private let eventLoop = MultiThreadedEventLoopGroup.singleton.next()
let benchmarks = {
let defaultMetrics: [BenchmarkMetric] = [
.mallocCountTotal,
.mallocCountTotal
]
Benchmark(
@@ -22,7 +22,7 @@ func runTCPEchoAsyncChannel(numberOfWrites: Int, eventLoop: EventLoop) async thr
port: 0
) { channel in
channel.eventLoop.makeCompletedFuture {
return try NIOAsyncChannel(
try NIOAsyncChannel(
wrappingChannelSynchronously: channel,
configuration: .init(
inboundType: ByteBuffer.self,
@@ -38,7 +38,7 @@ func runTCPEchoAsyncChannel(numberOfWrites: Int, eventLoop: EventLoop) async thr
port: serverChannel.channel.localAddress!.port!
) { channel in
channel.eventLoop.makeCompletedFuture {
return try NIOAsyncChannel(
try NIOAsyncChannel(
wrappingChannelSynchronously: channel,
configuration: .init(
inboundType: ByteBuffer.self,
@@ -55,7 +55,9 @@ func runTCPEchoAsyncChannel(numberOfWrites: Int, eventLoop: EventLoop) async thr
group.addTask {
try await serverChannel.executeThenClose { serverChannelInbound in
for try await connectionChannel in serverChannelInbound {
try await connectionChannel.executeThenClose { connectionChannelInbound, connectionChannelOutbound in
try await connectionChannel.executeThenClose {
connectionChannelInbound,
connectionChannelOutbound in
for try await inboundData in connectionChannelInbound {
try await connectionChannelOutbound.write(inboundData)
}
@@ -68,7 +70,7 @@ func runTCPEchoAsyncChannel(numberOfWrites: Int, eventLoop: EventLoop) async thr
// This child task is collecting the echoed back responses.
group.addTask {
var receivedData = 0
for try await inboundData in inbound {
for try await inboundData in inbound {
receivedData += inboundData.readableBytes
if receivedData == numberOfWrites * messageSize {
@@ -25,9 +25,9 @@ import Glibc
typealias EnqueueGlobalHook = @convention(thin) (UnownedJob, @convention(thin) (UnownedJob) -> Void) -> Void
var swiftTaskEnqueueGlobalHook: EnqueueGlobalHook? {
get { _swiftTaskEnqueueGlobalHook.pointee }
set { _swiftTaskEnqueueGlobalHook.pointee = newValue }
get { _swiftTaskEnqueueGlobalHook.pointee }
set { _swiftTaskEnqueueGlobalHook.pointee = newValue }
}
private let _swiftTaskEnqueueGlobalHook: UnsafeMutablePointer<EnqueueGlobalHook?> =
dlsym(dlopen(nil, RTLD_LAZY), "swift_task_enqueueGlobal_hook").assumingMemoryBound(to: EnqueueGlobalHook?.self)
dlsym(dlopen(nil, RTLD_LAZY), "swift_task_enqueueGlobal_hook").assumingMemoryBound(to: EnqueueGlobalHook?.self)
+1 -1
View File
@@ -5,7 +5,7 @@ import PackageDescription
let package = Package(
name: "benchmarks",
platforms: [
.macOS("14"),
.macOS("14")
],
dependencies: [
.package(path: "../"),
@@ -19,12 +19,13 @@ import PackageDescription
let package = Package(
name: "AtomicCounter",
products: [
.library(name: "AtomicCounter", type: .dynamic, targets: ["AtomicCounter"]),
.library(name: "AtomicCounter", type: .dynamic, targets: ["AtomicCounter"])
],
dependencies: [ ],
dependencies: [],
targets: [
.target(
name: "AtomicCounter",
dependencies: []),
dependencies: []
)
]
)
@@ -19,12 +19,12 @@ import PackageDescription
let package = Package(
name: "HookedFunctions",
products: [
.library(name: "HookedFunctions", type: .dynamic, targets: ["HookedFunctions"]),
.library(name: "HookedFunctions", type: .dynamic, targets: ["HookedFunctions"])
],
dependencies: [
.package(url: "../AtomicCounter/", branch: "main"),
.package(url: "../AtomicCounter/", branch: "main")
],
targets: [
.target(name: "HookedFunctions", dependencies: ["AtomicCounter"]),
.target(name: "HookedFunctions", dependencies: ["AtomicCounter"])
]
)
@@ -19,12 +19,12 @@ import PackageDescription
let package = Package(
name: "HookedFunctions",
products: [
.library(name: "HookedFunctions", type: .dynamic, targets: ["HookedFunctions"]),
.library(name: "HookedFunctions", type: .dynamic, targets: ["HookedFunctions"])
],
dependencies: [
.package(url: "../AtomicCounter/", branch: "main"),
.package(url: "../AtomicCounter/", branch: "main")
],
targets: [
.target(name: "HookedFunctions", dependencies: ["AtomicCounter"]),
.target(name: "HookedFunctions", dependencies: ["AtomicCounter"])
]
)
@@ -12,8 +12,9 @@
//
//===----------------------------------------------------------------------===//
import Foundation
import AtomicCounter
import Foundation
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
@@ -24,7 +25,7 @@ import Glibc
func waitForThreadsToQuiesce(shouldReachZero: Bool) {
func getUnfreed() -> Int {
return AtomicCounter.read_malloc_counter() - AtomicCounter.read_free_counter()
AtomicCounter.read_malloc_counter() - AtomicCounter.read_free_counter()
}
var oldNumberOfUnfreed = getUnfreed()
@@ -35,7 +36,8 @@ func waitForThreadsToQuiesce(shouldReachZero: Bool) {
return
}
count += 1
usleep(shouldReachZero ? 50_000 : 200_000) // allocs/frees happen on multiple threads, allow some cool down time
// allocs/frees happen on multiple threads, allow some cool down time
usleep(shouldReachZero ? 50_000 : 200_000)
let newNumberOfUnfreed = getUnfreed()
if oldNumberOfUnfreed == newNumberOfUnfreed && (!shouldReachZero || newNumberOfUnfreed <= 0) {
// nothing happened in the last 100ms, let's assume everything's
@@ -57,7 +59,11 @@ struct Measurement {
}
extension Array where Element == Measurement {
private func printIntegerMetric(_ keyPath: KeyPath<Measurement, Int>, description desc: String, metricName k: String) {
private func printIntegerMetric(
_ keyPath: KeyPath<Measurement, Int>,
description desc: String,
metricName k: String
) {
let vs = self.map { $0[keyPath: keyPath] }
print("\(desc).\(k): \(vs.min() ?? -1)")
}
@@ -90,13 +96,13 @@ func measureAll(trackFDs: Bool, _ fn: () -> Int) -> [Measurement] {
AtomicCounter.begin_tracking_fds()
}
#if canImport(Darwin)
#if canImport(Darwin)
autoreleasepool {
_ = fn()
}
#else
#else
_ = fn()
#endif
#endif
waitForThreadsToQuiesce(shouldReachZero: !throwAway)
let frees = AtomicCounter.read_free_counter()
let mallocs = AtomicCounter.read_malloc_counter()
@@ -121,7 +127,7 @@ func measureAll(trackFDs: Bool, _ fn: () -> Int) -> [Measurement] {
)
}
_ = measureOne(throwAway: true, trackFDs: trackFDs, fn) /* pre-heat and throw away */
_ = measureOne(throwAway: true, trackFDs: trackFDs, fn) // pre-heat and throw away
var measurements: [Measurement] = []
for _ in 0..<10 {
@@ -132,19 +138,19 @@ func measureAll(trackFDs: Bool, _ fn: () -> Int) -> [Measurement] {
return measurements
}
func measureAndPrint(desc: String, trackFDs: Bool, fn: () -> Int) -> Void {
func measureAndPrint(desc: String, trackFDs: Bool, fn: () -> Int) {
let measurements = measureAll(trackFDs: trackFDs, fn)
measurements.printTotalAllocations(description: desc)
measurements.printRemainingAllocations(description: desc)
measurements.printTotalAllocatedBytes(description: desc)
measurements.printLeakedFDs(description: desc)
print("DEBUG: \(measurements)")
}
public func measure(identifier: String, trackFDs: Bool = false, _ body: () -> Int) {
measureAndPrint(desc: identifier, trackFDs: trackFDs) {
return body()
body()
}
}
@@ -160,7 +166,7 @@ func measureAll(trackFDs: Bool, _ fn: @escaping () async -> Int) -> [Measurement
}
group.wait()
}
if trackFDs {
AtomicCounter.begin_tracking_fds()
}
@@ -169,13 +175,13 @@ func measureAll(trackFDs: Bool, _ fn: @escaping () async -> Int) -> [Measurement
AtomicCounter.reset_malloc_counter()
AtomicCounter.reset_malloc_bytes_counter()
#if canImport(Darwin)
#if canImport(Darwin)
autoreleasepool {
run(fn)
}
#else
#else
run(fn)
#endif
#endif
waitForThreadsToQuiesce(shouldReachZero: !throwAway)
let frees = AtomicCounter.read_free_counter()
let mallocs = AtomicCounter.read_malloc_counter()
@@ -200,7 +206,7 @@ func measureAll(trackFDs: Bool, _ fn: @escaping () async -> Int) -> [Measurement
)
}
_ = measureOne(throwAway: true, trackFDs: trackFDs, fn) /* pre-heat and throw away */
_ = measureOne(throwAway: true, trackFDs: trackFDs, fn) // pre-heat and throw away
var measurements: [Measurement] = []
for _ in 0..<10 {
@@ -212,7 +218,7 @@ func measureAll(trackFDs: Bool, _ fn: @escaping () async -> Int) -> [Measurement
}
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
func measureAndPrint(desc: String, trackFDs: Bool, fn: @escaping () async -> Int) -> Void {
func measureAndPrint(desc: String, trackFDs: Bool, fn: @escaping () async -> Int) {
let measurements = measureAll(trackFDs: trackFDs, fn)
measurements.printTotalAllocations(description: desc)
measurements.printRemainingAllocations(description: desc)
@@ -14,54 +14,56 @@
import Foundation
import NIOCore
import NIOPosix
import NIOHTTP1
import NIOPosix
let localhostPickPort = try! SocketAddress.makeAddressResolvingHost("127.0.0.1", port: 0)
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
final class RepeatedRequests: ChannelInboundHandler {
typealias InboundIn = HTTPClientResponsePart
typealias OutboundOut = HTTPClientRequestPart
typealias InboundIn = HTTPClientResponsePart
typealias OutboundOut = HTTPClientRequestPart
private let numberOfRequests: Int
private var remainingNumberOfRequests: Int
private let isDonePromise: EventLoopPromise<Int>
static var requestHead: HTTPRequestHead {
private let numberOfRequests: Int
private var remainingNumberOfRequests: Int
private let isDonePromise: EventLoopPromise<Int>
static var requestHead: HTTPRequestHead {
var head = HTTPRequestHead(version: .http1_1, method: .GET, uri: "/allocation-test-1")
head.headers.add(name: "Host", value: "foo-\(ObjectIdentifier(self)).com")
return head
}
head.headers.add(name: "Host", value: "foo-\(ObjectIdentifier(self)).com")
return head
}
init(numberOfRequests: Int, eventLoop: EventLoop) {
self.remainingNumberOfRequests = numberOfRequests
self.numberOfRequests = numberOfRequests
self.isDonePromise = eventLoop.makePromise()
}
init(numberOfRequests: Int, eventLoop: EventLoop) {
self.remainingNumberOfRequests = numberOfRequests
self.numberOfRequests = numberOfRequests
self.isDonePromise = eventLoop.makePromise()
}
func wait() throws -> Int {
let reqs = try self.isDonePromise.futureResult.wait()
precondition(reqs == self.numberOfRequests)
return reqs
}
func wait() throws -> Int {
let reqs = try self.isDonePromise.futureResult.wait()
precondition(reqs == self.numberOfRequests)
return reqs
}
func errorCaught(context: ChannelHandlerContext, error: Error) {
context.channel.close(promise: nil)
self.isDonePromise.fail(error)
}
func errorCaught(context: ChannelHandlerContext, error: Error) {
context.channel.close(promise: nil)
self.isDonePromise.fail(error)
}
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
let respPart = Self.unwrapInboundIn(data)
if case .end(nil) = respPart {
if self.remainingNumberOfRequests <= 0 {
context.channel.close().map { self.numberOfRequests - self.remainingNumberOfRequests }.cascade(to: self.isDonePromise)
} else {
self.remainingNumberOfRequests -= 1
context.write(Self.wrapOutboundOut(.head(RepeatedRequests.requestHead)), promise: nil)
context.writeAndFlush(Self.wrapOutboundOut(.end(nil)), promise: nil)
}
}
}
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
let respPart = self.unwrapInboundIn(data)
if case .end(nil) = respPart {
if self.remainingNumberOfRequests <= 0 {
context.channel.close().map { self.numberOfRequests - self.remainingNumberOfRequests }.cascade(
to: self.isDonePromise
)
} else {
self.remainingNumberOfRequests -= 1
context.write(self.wrapOutboundOut(.head(RepeatedRequests.requestHead)), promise: nil)
context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil)
}
}
}
}
private final class SimpleHTTPServer: ChannelInboundHandler {
@@ -94,10 +96,13 @@ private final class SimpleHTTPServer: ChannelInboundHandler {
}
public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
if case .head(let req) = Self.unwrapInboundIn(data), req.uri == "/allocation-test-1" {
context.write(Self.wrapOutboundOut(.head(self.responseHead)), promise: nil)
context.write(Self.wrapOutboundOut(.body(.byteBuffer(self.responseBody(allocator: context.channel.allocator)))), promise: nil)
context.writeAndFlush(Self.wrapOutboundOut(.end(nil)), promise: nil)
if case .head(let req) = self.unwrapInboundIn(data), req.uri == "/allocation-test-1" {
context.write(self.wrapOutboundOut(.head(self.responseHead)), promise: nil)
context.write(
self.wrapOutboundOut(.body(.byteBuffer(self.responseBody(allocator: context.channel.allocator)))),
promise: nil
)
context.writeAndFlush(self.wrapOutboundOut(.end(nil)), promise: nil)
}
}
}
@@ -106,8 +111,10 @@ func doRequests(group: EventLoopGroup, number numberOfRequests: Int) throws -> I
let serverChannel = try ServerBootstrap(group: group)
.serverChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
.childChannelInitializer { channel in
channel.pipeline.configureHTTPServerPipeline(withPipeliningAssistance: true,
withErrorHandling: false).flatMap {
channel.pipeline.configureHTTPServerPipeline(
withPipeliningAssistance: true,
withErrorHandling: false
).flatMap {
channel.pipeline.addHandler(SimpleHTTPServer())
}
}.bind(to: localhostPickPort).wait()
@@ -116,7 +123,6 @@ func doRequests(group: EventLoopGroup, number numberOfRequests: Int) throws -> I
try! serverChannel.close().wait()
}
let repeatedRequestsHandler = RepeatedRequests(numberOfRequests: numberOfRequests, eventLoop: group.next())
let clientChannel = try ClientBootstrap(group: group)
@@ -176,42 +182,42 @@ enum UDPShared {
public typealias InboundIn = AddressedEnvelope<ByteBuffer>
public typealias OutboundOut = AddressedEnvelope<ByteBuffer>
private var repetitionsRemaining: Int
private let remoteAddress: SocketAddress
init(remoteAddress: SocketAddress, numberOfRepetitions: Int) {
self.remoteAddress = remoteAddress
self.repetitionsRemaining = numberOfRepetitions
}
public func channelActive(context: ChannelHandlerContext) {
// Channel is available. It's time to send the message to the server to initialize the ping-pong sequence.
self.sendSomeDataIfDesiredOrClose(context: context)
}
private func sendSomeDataIfDesiredOrClose(context: ChannelHandlerContext) {
if repetitionsRemaining > 0 {
repetitionsRemaining -= 1
// Set the transmission data.
let line = "Something to send there and back again."
let buffer = context.channel.allocator.buffer(string: line)
// Forward the data.
let envolope = AddressedEnvelope<ByteBuffer>(remoteAddress: remoteAddress, data: buffer)
context.writeAndFlush(Self.wrapOutboundOut(envolope), promise: nil)
context.writeAndFlush(self.wrapOutboundOut(envolope), promise: nil)
} else {
// We're all done - hurrah!
context.close(promise: nil)
}
}
public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
// Got back a response - maybe send some more.
self.sendSomeDataIfDesiredOrClose(context: context)
}
public func errorCaught(context: ChannelHandlerContext, error: Error) {
// Errors should never happen.
fatalError("EchoHandlerClient received errorCaught")
@@ -222,20 +228,24 @@ enum UDPShared {
let serverChannel = try DatagramBootstrap(group: group)
// Set the handlers that are applied to the bound channel
.channelInitializer { channel in
return channel.pipeline.addHandler(EchoHandler())
channel.pipeline.addHandler(EchoHandler())
}
.bind(to: localhostPickPort).wait()
defer {
try! serverChannel.close().wait()
}
let remoteAddress = serverChannel.localAddress!
let clientChannel = try DatagramBootstrap(group: group)
.channelInitializer { channel in
channel.pipeline.addHandler(EchoHandlerClient(remoteAddress: remoteAddress,
numberOfRepetitions: numberOfRequests))
channel.pipeline.addHandler(
EchoHandlerClient(
remoteAddress: remoteAddress,
numberOfRepetitions: numberOfRequests
)
)
}
.bind(to: localhostPickPort).wait()
@@ -15,10 +15,12 @@
import NIOCore
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
fileprivate typealias SequenceProducer = NIOAsyncSequenceProducer<Int, NIOAsyncSequenceProducerBackPressureStrategies.HighLowWatermark, Delegate>
private typealias SequenceProducer = NIOAsyncSequenceProducer<
Int, NIOAsyncSequenceProducerBackPressureStrategies.HighLowWatermark, Delegate
>
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
fileprivate final class Delegate: NIOAsyncSequenceProducerDelegate, @unchecked Sendable {
private final class Delegate: NIOAsyncSequenceProducerDelegate, @unchecked Sendable {
private let elements = Array(repeating: 1, count: 1000)
var source: SequenceProducer.Source!
@@ -36,7 +38,10 @@ func run(identifier: String) {
}
measure(identifier: identifier) {
let delegate = Delegate()
let producer = SequenceProducer.makeSequence(backPressureStrategy: .init(lowWatermark: 100, highWatermark: 500), delegate: delegate)
let producer = SequenceProducer.makeSequence(
backPressureStrategy: .init(lowWatermark: 100, highWatermark: 500),
delegate: delegate
)
let sequence = producer.sequence
delegate.source = producer.source
@@ -44,7 +49,7 @@ func run(identifier: String) {
for await i in sequence {
counter += i
if counter == 10000000 {
if counter == 10_000_000 {
return counter
}
}
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
import NIOCore
import DequeModule
import NIOCore
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
fileprivate struct Delegate: NIOAsyncWriterSinkDelegate, Sendable {
private struct Delegate: NIOAsyncWriterSinkDelegate, Sendable {
typealias Element = Int
func didYield(contentsOf sequence: Deque<Int>) {}
@@ -33,10 +33,10 @@ func run(identifier: String) {
let newWriter = NIOAsyncWriter<Int, Delegate>.makeWriter(isWritable: true, delegate: delegate)
let writer = newWriter.writer
for i in 0..<1000000 {
for i in 0..<1_000_000 {
try! await writer.yield(i)
}
return 1000000
return 1_000_000
}
}
@@ -15,7 +15,7 @@
import NIOCore
import NIOEmbedded
fileprivate final class SimpleHandler: ChannelInboundHandler {
private final class SimpleHandler: ChannelInboundHandler {
typealias InboundIn = NIOAny
}
@@ -29,7 +29,7 @@ func run(identifier: String) {
}
try! channel.pipeline.addHandlers([
SimpleHandler(),
SimpleHandler()
SimpleHandler(),
]).wait()
}
return iterations
@@ -15,7 +15,7 @@
import NIOCore
import NIOEmbedded
fileprivate final class SimpleHandler: ChannelInboundHandler {
private final class SimpleHandler: ChannelInboundHandler {
typealias InboundIn = NIOAny
}
@@ -28,8 +28,8 @@ func run(identifier: String) {
_ = try! channel.finish()
}
try! channel.pipeline.syncOperations.addHandlers([
SimpleHandler(),
SimpleHandler()
SimpleHandler(),
SimpleHandler(),
])
}
return iterations
@@ -15,7 +15,7 @@
import NIOCore
import NIOEmbedded
fileprivate final class RemovableHandler: ChannelInboundHandler, RemovableChannelHandler {
private final class RemovableHandler: ChannelInboundHandler, RemovableChannelHandler {
typealias InboundIn = NIOAny
static let name: String = "RemovableHandler"
@@ -32,7 +32,10 @@ fileprivate final class RemovableHandler: ChannelInboundHandler, RemovableChanne
}
@inline(__always)
private func addRemoveBench(iterations: Int, _ removalOperation: (Channel, RemovableHandler) -> EventLoopFuture<Void>) -> Int {
private func addRemoveBench(
iterations: Int,
_ removalOperation: (Channel, RemovableHandler) -> EventLoopFuture<Void>
) -> Int {
let channel = EmbeddedChannel()
defer {
_ = try! channel.finish()
@@ -22,8 +22,8 @@ func run(identifier: String) {
}
let server = try! ServerBootstrap(group: group)
.bind(host: "127.0.0.1", port: 0)
.wait()
.bind(host: "127.0.0.1", port: 0)
.wait()
defer {
try! server.close().wait()
}
@@ -15,7 +15,7 @@
import NIOCore
import NIOEmbedded
fileprivate final class SimpleHandler: ChannelInboundHandler {
private final class SimpleHandler: ChannelInboundHandler {
typealias InboundIn = NIOAny
}
@@ -15,7 +15,7 @@
import NIOCore
import NIOEmbedded
fileprivate final class SimpleHandler: ChannelInboundHandler {
private final class SimpleHandler: ChannelInboundHandler {
typealias InboundIn = NIOAny
}
@@ -35,7 +35,7 @@ func run(identifier: String) {
let serverConnection = try! ServerBootstrap(group: group)
.bind(host: "localhost", port: 0)
.wait()
let serverAddress = serverConnection.localAddress!
let clientBootstrap = ClientBootstrap(group: group)
.channelInitializer { channel in
@@ -48,7 +48,7 @@ func run(identifier: String) {
let iterations = 1000
for _ in 0..<iterations {
let conn = clientBootstrap.connect(to: serverAddress)
let _: Void? = try? conn.flatMap { channel in
(channel as! SocketOptionProvider).setSoLinger(linger(l_onoff: 1, l_linger: 0)).flatMap {
channel.closeFuture
@@ -15,7 +15,7 @@
import NIOCore
import NIOPosix
fileprivate final class DoNothingHandler: ChannelInboundHandler {
private final class DoNothingHandler: ChannelInboundHandler {
public typealias InboundIn = ByteBuffer
public typealias OutboundOut = ByteBuffer
}
@@ -24,7 +24,7 @@ func run(identifier: String) {
measure(identifier: identifier) {
let numberOfIterations = 1000
let doNothingHandler = DoNothingHandler()
for _ in 0 ..< numberOfIterations {
for _ in 0..<numberOfIterations {
_ = ClientBootstrap(group: group)
.channelInitializer { channel in
channel.pipeline.addHTTPClientHandlers().flatMap {
@@ -15,7 +15,7 @@
import NIOCore
import NIOPosix
fileprivate final class ReceiveAndCloseHandler: ChannelInboundHandler {
private final class ReceiveAndCloseHandler: ChannelInboundHandler {
public typealias InboundIn = ByteBuffer
public typealias OutboundOut = ByteBuffer
@@ -30,15 +30,15 @@ fileprivate final class ReceiveAndCloseHandler: ChannelInboundHandler {
}
}
fileprivate final class LingerSettingHandler: ChannelInboundHandler {
private final class LingerSettingHandler: ChannelInboundHandler {
typealias InboundIn = ByteBuffer
typealias OutboundOut = ByteBuffer
public func handlerAdded(context: ChannelHandlerContext) {
(context.channel as? SocketOptionProvider)?.setSoLinger(linger(l_onoff: 1, l_linger: 0))
.whenFailure({ error in fatalError("Failed to set linger \(error)") })
}
func errorCaught(context: ChannelHandlerContext, error: Error) {
fatalError("unexpected \(error)")
}
@@ -51,10 +51,10 @@ func run(identifier: String) {
}
let serverChannel = try! ServerBootstrap(group: group)
.serverChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
.childChannelInitializer { channel in
channel.pipeline.addHandler(ReceiveAndCloseHandler())
}.bind(host: "127.0.0.1", port: 0).wait()
.serverChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
.childChannelInitializer { channel in
channel.pipeline.addHandler(ReceiveAndCloseHandler())
}.bind(host: "127.0.0.1", port: 0).wait()
defer {
try! serverChannel.close().wait()
}
@@ -70,7 +70,7 @@ func run(identifier: String) {
let buffer = ByteBuffer(integer: 1, as: UInt8.self)
let el = group.next()
for _ in 0 ..< numberOfIterations {
for _ in 0..<numberOfIterations {
try! el.flatSubmit {
clientBootstrap.connect(to: serverAddress).flatMap { (clientChannel) -> EventLoopFuture<Void> in
writeWaitAndClose(clientChannel: clientChannel, buffer: buffer)
@@ -82,9 +82,9 @@ func run(identifier: String) {
}
}
fileprivate func writeWaitAndClose(clientChannel: Channel, buffer: ByteBuffer) -> EventLoopFuture<Void> {
private func writeWaitAndClose(clientChannel: Channel, buffer: ByteBuffer) -> EventLoopFuture<Void> {
// Send a byte to make sure everything is really open.
return clientChannel.writeAndFlush(buffer).flatMap {
clientChannel.writeAndFlush(buffer).flatMap {
clientChannel.closeFuture
}
}
@@ -15,7 +15,7 @@
import NIOCore
import NIOPosix
fileprivate final class ServerEchoHandler: ChannelInboundHandler {
private final class ServerEchoHandler: ChannelInboundHandler {
public typealias InboundIn = AddressedEnvelope<ByteBuffer>
public typealias OutboundOut = AddressedEnvelope<ByteBuffer>
@@ -35,19 +35,19 @@ fileprivate final class ServerEchoHandler: ChannelInboundHandler {
}
}
fileprivate final class ClientHandler: ChannelInboundHandler {
private final class ClientHandler: ChannelInboundHandler {
public typealias InboundIn = AddressedEnvelope<ByteBuffer>
public typealias OutboundOut = AddressedEnvelope<ByteBuffer>
private let remoteAddress: SocketAddress
init(remoteAddress: SocketAddress) {
self.remoteAddress = remoteAddress
}
public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
// If we still have iterations to do send some more data.
if (self.iterationsOutstanding > 0) {
if self.iterationsOutstanding > 0 {
self.iterationsOutstanding -= 1
sendBytes(clientChannel: context.channel)
} else {
@@ -63,10 +63,10 @@ fileprivate final class ClientHandler: ChannelInboundHandler {
public func errorCaught(context: ChannelHandlerContext, error: Error) {
fatalError()
}
var iterationsOutstanding = 0
var whenDone: EventLoopPromise<Void>? = nil
private func sendBytes(clientChannel: Channel) {
var buffer = clientChannel.allocator.buffer(capacity: 1)
buffer.writeInteger(3, as: UInt8.self)
@@ -75,10 +75,10 @@ fileprivate final class ClientHandler: ChannelInboundHandler {
let envelope = AddressedEnvelope<ByteBuffer>(remoteAddress: remoteAddress, data: buffer, metadata: metadata)
clientChannel.writeAndFlush(Self.wrapOutboundOut(envelope), promise: nil)
}
func sendBytesAndWaitForReply(clientChannel: Channel) -> Int {
let numberOfIterations = 1000
// Setup for iteration.
self.iterationsOutstanding = numberOfIterations
self.whenDone = clientChannel.eventLoop.makePromise()
@@ -95,7 +95,7 @@ func run(identifier: String) {
.channelOption(ChannelOptions.explicitCongestionNotification, value: true)
// Set the handlers that are applied to the bound channel
.channelInitializer { channel in
return channel.pipeline.addHandler(ServerEchoHandler())
channel.pipeline.addHandler(ServerEchoHandler())
}
.bind(to: localhostPickPort).wait()
defer {
@@ -114,9 +114,8 @@ func run(identifier: String) {
defer {
try! clientChannel.close().wait()
}
measure(identifier: identifier) {
clientHandler.sendBytesAndWaitForReply(clientChannel: clientChannel)
}
}
@@ -15,7 +15,7 @@
import NIOCore
import NIOPosix
fileprivate final class DoNothingHandler: ChannelInboundHandler {
private final class DoNothingHandler: ChannelInboundHandler {
public typealias InboundIn = ByteBuffer
public typealias OutboundOut = ByteBuffer
}
@@ -23,7 +23,7 @@ fileprivate final class DoNothingHandler: ChannelInboundHandler {
func run(identifier: String) {
measure(identifier: identifier) {
let numberOfIterations = 1000
for _ in 0 ..< numberOfIterations {
for _ in 0..<numberOfIterations {
_ = DatagramBootstrap(group: group)
.channelInitializer { channel in
channel.pipeline.addHandler(DoNothingHandler())
@@ -15,22 +15,22 @@
import NIOCore
import NIOPosix
fileprivate final class CountReadsHandler: ChannelInboundHandler {
private final class CountReadsHandler: ChannelInboundHandler {
public typealias InboundIn = ByteBuffer
public typealias OutboundOut = ByteBuffer
private var readsRemaining: Int
private let completed: EventLoopPromise<Void>
var completionFuture: EventLoopFuture<Void> {
return self.completed.futureResult
self.completed.futureResult
}
init(numberOfReadsExpected: Int, completionPromise: EventLoopPromise<Void>) {
self.readsRemaining = numberOfReadsExpected
self.completed = completionPromise
}
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
self.readsRemaining -= 1
if self.readsRemaining <= 0 {
@@ -41,13 +41,15 @@ fileprivate final class CountReadsHandler: ChannelInboundHandler {
func run(identifier: String) {
let numberOfIterations = 1000
let serverHandler = CountReadsHandler(numberOfReadsExpected: numberOfIterations,
completionPromise: group.next().makePromise())
let serverHandler = CountReadsHandler(
numberOfReadsExpected: numberOfIterations,
completionPromise: group.next().makePromise()
)
let serverChannel = try! DatagramBootstrap(group: group)
// Set the handlers that are applied to the bound channel
.channelInitializer { channel in
return channel.pipeline.addHandler(serverHandler)
channel.pipeline.addHandler(serverHandler)
}
.bind(to: localhostPickPort).wait()
defer {
@@ -55,13 +57,13 @@ func run(identifier: String) {
}
let remoteAddress = serverChannel.localAddress!
let clientBootstrap = DatagramBootstrap(group: group)
measure(identifier: identifier) {
let buffer = ByteBuffer(integer: 1, as: UInt8.self)
for _ in 0 ..< numberOfIterations {
try! clientBootstrap.bind(to: localhostPickPort).flatMap { clientChannel -> EventLoopFuture<Void> in
for _ in 0..<numberOfIterations {
try! clientBootstrap.bind(to: localhostPickPort).flatMap { clientChannel -> EventLoopFuture<Void> in
// Send a byte to make sure everything is really open.
let envelope = AddressedEnvelope<ByteBuffer>(remoteAddress: remoteAddress, data: buffer)
return clientChannel.writeAndFlush(envelope).flatMap {
@@ -73,4 +75,3 @@ func run(identifier: String) {
return numberOfIterations
}
}
@@ -25,7 +25,7 @@ func run(identifier: String) {
let substring = Substring("A")
@inline(never)
func doWrites(buffer: inout ByteBuffer, dispatchData: DispatchData, substring: Substring) {
/* these ones are zero allocations */
// these ones are zero allocations
// buffer.writeBytes(foundationData) // see SR-7542
buffer.writeBytes([0x41])
buffer.writeBytes("A".utf8)
@@ -33,15 +33,15 @@ func run(identifier: String) {
buffer.writeStaticString("A")
buffer.writeInteger(0x41, as: UInt8.self)
/* those down here should be one allocation each (on Linux) */
buffer.writeBytes(dispatchData) // see https://bugs.swift.org/browse/SR-9597
// those down here should be one allocation each (on Linux)
buffer.writeBytes(dispatchData) // see https://bugs.swift.org/browse/SR-9597
/* these here are one allocation on all platforms */
// these here are one allocation on all platforms
buffer.writeSubstring(substring)
}
@inline(never)
func doReads(buffer: inout ByteBuffer) {
/* these ones are zero allocations */
// these ones are zero allocations
let val = buffer.readInteger(as: UInt8.self)
precondition(0x41 == val, "\(val!)")
var slice = buffer.readSlice(length: 1)
@@ -51,13 +51,13 @@ func run(identifier: String) {
precondition(ptr[0] == 0x41)
}
/* those down here should be one allocation each */
// those down here should be one allocation each
let arr = buffer.readBytes(length: 1)
precondition([0x41] == arr!, "\(arr!)")
let str = buffer.readString(length: 1)
precondition("A" == str, "\(str!)")
}
for _ in 0..<1000 {
for _ in 0..<1000 {
doWrites(buffer: &buffer, dispatchData: dispatchData, substring: substring)
doReads(buffer: &buffer)
}
@@ -30,7 +30,7 @@ func run(identifier: String) {
let channel = EmbeddedChannel()
try! channel.pipeline.addHandler(ByteToMessageHandler(WebSocketFrameDecoder())).wait()
try! channel.pipeline.addHandler(UnboxingChannelHandler()).wait()
let data = ByteBuffer(bytes: [0x81, 0x00]) // empty websocket
let data = ByteBuffer(bytes: [0x81, 0x00]) // empty websocket
measure(identifier: identifier) {
for _ in 0..<1000 {
@@ -16,7 +16,13 @@ import NIOCore
import NIOEmbedded
import NIOWebSocket
func doSendFramesHoldingBuffer(channel: EmbeddedChannel, number numberOfFrameSends: Int, data originalData: [UInt8], spareBytesAtFront: Int, mask: WebSocketMaskingKey? = nil) throws -> Int {
func doSendFramesHoldingBuffer(
channel: EmbeddedChannel,
number numberOfFrameSends: Int,
data originalData: [UInt8],
spareBytesAtFront: Int,
mask: WebSocketMaskingKey? = nil
) throws -> Int {
var data = channel.allocator.buffer(capacity: originalData.count + spareBytesAtFront)
data.moveWriterIndex(forwardBy: spareBytesAtFront)
data.moveReaderIndex(forwardBy: spareBytesAtFront)
@@ -35,8 +41,13 @@ func doSendFramesHoldingBuffer(channel: EmbeddedChannel, number numberOfFrameSen
return numberOfFrameSends
}
func doSendFramesNewBuffer(channel: EmbeddedChannel, number numberOfFrameSends: Int, data originalData: [UInt8], spareBytesAtFront: Int, mask: WebSocketMaskingKey? = nil) throws -> Int {
func doSendFramesNewBuffer(
channel: EmbeddedChannel,
number numberOfFrameSends: Int,
data originalData: [UInt8],
spareBytesAtFront: Int,
mask: WebSocketMaskingKey? = nil
) throws -> Int {
for _ in 0..<numberOfFrameSends {
// We need a new allocation every time to drop the original data ref.
var data = channel.allocator.buffer(capacity: originalData.count + spareBytesAtFront)
@@ -55,7 +66,6 @@ func doSendFramesNewBuffer(channel: EmbeddedChannel, number numberOfFrameSends:
return numberOfFrameSends
}
func run(identifier: String) {
let maskKey: WebSocketMaskingKey = [1, 2, 3, 4]
let channel = EmbeddedChannel()
@@ -63,25 +73,47 @@ func run(identifier: String) {
let data = Array(repeating: UInt8(0), count: 1024)
measure(identifier: identifier + "_holding_buffer") {
let numberDone = try! doSendFramesHoldingBuffer(channel: channel, number: 1000, data: data, spareBytesAtFront: 0)
let numberDone = try! doSendFramesHoldingBuffer(
channel: channel,
number: 1000,
data: data,
spareBytesAtFront: 0
)
precondition(numberDone == 1000)
return numberDone
}
measure(identifier: identifier + "_holding_buffer_with_space") {
let numberDone = try! doSendFramesHoldingBuffer(channel: channel, number: 1000, data: data, spareBytesAtFront: 8)
let numberDone = try! doSendFramesHoldingBuffer(
channel: channel,
number: 1000,
data: data,
spareBytesAtFront: 8
)
precondition(numberDone == 1000)
return numberDone
}
measure(identifier: identifier + "_holding_buffer_with_mask") {
let numberDone = try! doSendFramesHoldingBuffer(channel: channel, number: 1000, data: data, spareBytesAtFront: 0, mask: maskKey)
let numberDone = try! doSendFramesHoldingBuffer(
channel: channel,
number: 1000,
data: data,
spareBytesAtFront: 0,
mask: maskKey
)
precondition(numberDone == 1000)
return numberDone
}
measure(identifier: identifier + "_holding_buffer_with_space_with_mask") {
let numberDone = try! doSendFramesHoldingBuffer(channel: channel, number: 1000, data: data, spareBytesAtFront: 8, mask: maskKey)
let numberDone = try! doSendFramesHoldingBuffer(
channel: channel,
number: 1000,
data: data,
spareBytesAtFront: 8,
mask: maskKey
)
precondition(numberDone == 1000)
return numberDone
}
@@ -99,13 +131,25 @@ func run(identifier: String) {
}
measure(identifier: identifier + "_new_buffer_with_mask") {
let numberDone = try! doSendFramesNewBuffer(channel: channel, number: 1000, data: data, spareBytesAtFront: 0, mask: maskKey)
let numberDone = try! doSendFramesNewBuffer(
channel: channel,
number: 1000,
data: data,
spareBytesAtFront: 0,
mask: maskKey
)
precondition(numberDone == 1000)
return numberDone
}
measure(identifier: identifier + "_new_buffer_with_space_with_mask") {
let numberDone = try! doSendFramesNewBuffer(channel: channel, number: 1000, data: data, spareBytesAtFront: 8, mask: maskKey)
let numberDone = try! doSendFramesNewBuffer(
channel: channel,
number: 1000,
data: data,
spareBytesAtFront: 8,
mask: maskKey
)
precondition(numberDone == 1000)
return numberDone
}
@@ -33,7 +33,7 @@ func run(identifier: String) {
}
let el = EmbeddedEventLoop()
for _ in 0..<1000 {
for _ in 0..<1000 {
doEraseResult(loop: el)
}
return 1000
@@ -17,22 +17,22 @@ import NIOEmbedded
func run(identifier: String) {
measure(identifier: identifier) {
struct MyError: Error { }
struct MyError: Error {}
@inline(never)
func doThenAndFriends(loop: EventLoop) {
let p = loop.makePromise(of: Int.self)
let f = p.futureResult.flatMap { (r: Int) -> EventLoopFuture<Int> in
// This call allocates a new Future, and
// so does flatMap(), so this is two Futures.
return loop.makeSucceededFuture(r + 1)
loop.makeSucceededFuture(r + 1)
}.flatMapThrowing { (r: Int) -> Int in
// flatMapThrowing allocates a new Future, and calls `flatMap`
// which also allocates, so this is two.
return r + 2
r + 2
}.map { (r: Int) -> Int in
// map allocates a new future, and calls `flatMap` which
// also allocates, so this is two.
return r + 2
r + 2
}.flatMapThrowing { (r: Int) -> Int in
// flatMapThrowing allocates a future on the error path and
// calls `flatMap`, which also allocates, so this is two.
@@ -40,7 +40,7 @@ func run(identifier: String) {
}.flatMapError { (err: Error) -> EventLoopFuture<Int> in
// This call allocates a new Future, and so does flatMapError,
// so this is two Futures.
return loop.makeFailedFuture(err)
loop.makeFailedFuture(err)
}.flatMapErrorThrowing { (err: Error) -> Int in
// flatMapError allocates a new Future, and calls flatMapError,
// so this is two Futures
@@ -48,7 +48,7 @@ func run(identifier: String) {
}.recover { (err: Error) -> Int in
// recover allocates a future, and calls flatMapError, so
// this is two Futures.
return 1
1
}
p.succeed(0)
@@ -65,10 +65,10 @@ func run(identifier: String) {
// and(result:) allocate two.
let f = p1.futureResult
.and(p2.futureResult)
.and(p3.futureResult)
.and(value: 1)
.and(value: 1)
.and(p2.futureResult)
.and(p3.futureResult)
.and(value: 1)
.and(value: 1)
p1.succeed(1)
p2.succeed(1)
@@ -76,7 +76,7 @@ func run(identifier: String) {
_ = try! f.wait()
}
let el = EmbeddedEventLoop()
for _ in 0..<1000 {
for _ in 0..<1000 {
doThenAndFriends(loop: el)
doAnd(loop: el)
}
@@ -15,7 +15,7 @@
import NIOCore
func run(identifier: String) {
var buffer = CircularBuffer<Array<Int>>(initialCapacity: 100)
var buffer = CircularBuffer<[Int]>(initialCapacity: 100)
for _ in 0..<100 {
buffer.append([])
}
@@ -35,8 +35,12 @@ private final class PongDecoder: ByteToMessageDecoder {
}
}
public func decodeLast(context: ChannelHandlerContext, buffer: inout ByteBuffer, seenEOF: Bool) throws -> DecodingState {
return .needMoreData
public func decodeLast(
context: ChannelHandlerContext,
buffer: inout ByteBuffer,
seenEOF: Bool
) throws -> DecodingState {
.needMoreData
}
}
@@ -69,9 +73,8 @@ private final class PingHandler: ChannelInboundHandler {
}
public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
var buf = Self.unwrapInboundIn(data)
if buf.readableBytes == 1 &&
buf.readInteger(as: UInt8.self) == PongHandler.pongCode {
var buf = self.unwrapInboundIn(data)
if buf.readableBytes == 1 && buf.readInteger(as: UInt8.self) == PongHandler.pongCode {
if self.remainingNumberOfRequests > 0 {
self.remainingNumberOfRequests -= 1
context.writeAndFlush(Self.wrapOutboundOut(self.pingBuffer), promise: nil)
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
import Foundation
import Dispatch
import Foundation
import NIOConcurrencyHelpers
import NIOCore
import NIOPosix
import NIOConcurrencyHelpers
func run(identifier: String) {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
@@ -37,27 +37,33 @@ func run(identifier: String) {
var fileBuffer = allocator.buffer(capacity: numberOfChunks)
fileBuffer.writeString(String(repeating: "X", count: numberOfChunks))
let path = NSTemporaryDirectory() + "/\(UUID())"
let fileHandle = try! NIOFileHandle(path: path,
mode: [.write, .read],
flags: .allowFileCreation(posixMode: 0o600))
let fileHandle = try! NIOFileHandle(
path: path,
mode: [.write, .read],
flags: .allowFileCreation(posixMode: 0o600)
)
defer {
unlink(path)
}
try! fileIO.write(fileHandle: fileHandle,
buffer: fileBuffer,
eventLoop: loop).wait()
try! fileIO.write(
fileHandle: fileHandle,
buffer: fileBuffer,
eventLoop: loop
).wait()
let numberOfBytes = NIOAtomic<Int>.makeAtomic(value: 0)
measure(identifier: identifier) {
numberOfBytes.store(0)
try! fileIO.readChunked(fileHandle: fileHandle,
fromOffset: 0,
byteCount: numberOfChunks,
chunkSize: 1,
allocator: allocator,
eventLoop: loop) { buffer in
numberOfBytes.add(buffer.readableBytes)
return loop.makeSucceededFuture(())
try! fileIO.readChunked(
fileHandle: fileHandle,
fromOffset: 0,
byteCount: numberOfChunks,
chunkSize: 1,
allocator: allocator,
eventLoop: loop
) { buffer in
numberOfBytes.add(buffer.readableBytes)
return loop.makeSucceededFuture(())
}.wait()
precondition(numberOfBytes.load() == numberOfChunks, "\(numberOfBytes.load()), \(numberOfChunks)")
return numberOfBytes.load()
+15 -15
View File
@@ -18,9 +18,9 @@ import PackageDescription
let swiftAtomics: PackageDescription.Target.Dependency = .product(name: "Atomics", package: "swift-atomics")
let swiftCollections: PackageDescription.Target.Dependency = .product(name: "DequeModule", package: "swift-collections")
let swiftSystem: PackageDescription.Target.Dependency = .product(
name: "SystemPackage",
package: "swift-system",
condition: .when(platforms: [.macOS, .iOS, .tvOS, .watchOS, .linux, .android])
name: "SystemPackage",
package: "swift-system",
condition: .when(platforms: [.macOS, .iOS, .tvOS, .watchOS, .linux, .android])
)
// This doesn't work when cross-compiling: the privacy manifest will be included in the Bundle and
@@ -121,7 +121,7 @@ let package = Package(
name: "CNIOAtomics",
dependencies: [],
cSettings: [
.define("_GNU_SOURCE"),
.define("_GNU_SOURCE")
]
),
.target(
@@ -132,14 +132,14 @@ let package = Package(
name: "CNIOLinux",
dependencies: [],
cSettings: [
.define("_GNU_SOURCE"),
.define("_GNU_SOURCE")
]
),
.target(
name: "CNIODarwin",
dependencies: [],
cSettings: [
.define("__APPLE_USE_RFC_3542"),
.define("__APPLE_USE_RFC_3542")
]
),
.target(
@@ -149,7 +149,7 @@ let package = Package(
.target(
name: "NIOConcurrencyHelpers",
dependencies: [
"CNIOAtomics",
"CNIOAtomics"
]
),
.target(
@@ -159,7 +159,7 @@ let package = Package(
"NIOCore",
"NIOConcurrencyHelpers",
"CNIOLLHTTP",
swiftCollections
swiftCollections,
]
),
.target(
@@ -169,14 +169,14 @@ let package = Package(
"NIOCore",
"NIOHTTP1",
"CNIOSHA1",
"_NIOBase64"
"_NIOBase64",
]
),
.target(
name: "CNIOLLHTTP",
cSettings: [
.define("_GNU_SOURCE"),
.define("LLHTTP_STRICT_MODE")
.define("_GNU_SOURCE"),
.define("LLHTTP_STRICT_MODE"),
]
),
.target(
@@ -218,14 +218,14 @@ let package = Package(
.target(
name: "NIOFileSystem",
dependencies: [
"_NIOFileSystem",
"_NIOFileSystem"
],
path: "Sources/_NIOFileSystemExported"
),
.target(
name: "_NIOFileSystemFoundationCompat",
dependencies: [
"_NIOFileSystem",
"_NIOFileSystem"
],
path: "Sources/NIOFileSystemFoundationCompat"
),
@@ -503,7 +503,7 @@ let package = Package(
// Contains known files and directory structures used
// for the integration tests. Exclude the whole tree from
// the build.
"Test Data",
"Test Data"
]
),
.testTarget(
@@ -512,7 +512,7 @@ let package = Package(
"_NIOFileSystem",
"_NIOFileSystemFoundationCompat",
]
)
),
]
)
+93 -93
View File
@@ -1,103 +1,103 @@
// snippet.hide
import _NIOFileSystem
import NIOCore
import _NIOFileSystem
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
func main() async throws
{
// snippet.show
func main() async throws {
// snippet.show
// NIOFileSystem provides access to the local file system via the FileSystem
// type which is available as a global shared instance.
let fileSystem = FileSystem.shared
// NIOFileSystem provides access to the local file system via the FileSystem
// type which is available as a global shared instance.
let fileSystem = FileSystem.shared
// Files can be inspected by using 'info':
if let info = try await fileSystem.info(forFileAt: "/Users/hal9000/demise-of-dave.txt") {
print("demise-of-dave.txt has type '\(info.type)'")
} else {
print("demise-of-dave.txt doesn't exist")
}
// Files can be inspected by using 'info':
if let info = try await fileSystem.info(forFileAt: "/Users/hal9000/demise-of-dave.txt") {
print("demise-of-dave.txt has type '\(info.type)'")
} else {
print("demise-of-dave.txt doesn't exist")
}
// Let's find out what's in that file.
do {
// Reading a whole file requires a limit. If the file is larger than the limit
// then an error is thrown. This avoids accidentally consuming too much memory
// if the file is larger than expected.
let plan = try await ByteBuffer(
contentsOf: "/Users/hal9000/demise-of-dave.txt",
maximumSizeAllowed: .mebibytes(1)
)
print("Plan for Dave's demise:", String(decoding: plan.readableBytesView, as: UTF8.self))
} catch let error as FileSystemError where error.code == .notFound {
// All errors thrown by the module have type FileSystemError (or
// Swift.CancellationError). It looks like the file doesn't exist. Let's
// create it now.
// Let's find out what's in that file.
do {
// Reading a whole file requires a limit. If the file is larger than the limit
// then an error is thrown. This avoids accidentally consuming too much memory
// if the file is larger than expected.
let plan = try await ByteBuffer(
contentsOf: "/Users/hal9000/demise-of-dave.txt",
maximumSizeAllowed: .mebibytes(1)
)
print("Plan for Dave's demise:", String(decoding: plan.readableBytesView, as: UTF8.self))
} catch let error as FileSystemError where error.code == .notFound {
// All errors thrown by the module have type FileSystemError (or
// Swift.CancellationError). It looks like the file doesn't exist. Let's
// create it now.
//
// The code above for reading the file is shorthand for opening the file in
// read-only mode and then reading its contents. The FileSystemProtocol
// has a few different 'withFileHandle' methods for opening a file in different
// modes. Let's open a file for writing, creating it at the same time.
try await fileSystem.withFileHandle(
forWritingAt: "/Users/hal9000/demise-of-dave.txt",
options: .newFile(replaceExisting: false)
) { file in
let plan = ByteBuffer(string: "TODO...")
try await file.write(contentsOf: plan.readableBytesView, toAbsoluteOffset: 0)
}
}
// Directories can be opened like regular files but they cannot be read from or
// written to. However, their contents can be listed:
let path: FilePath? = try await fileSystem.withDirectoryHandle(atPath: "/Users/hal9000/Music") { directory in
for try await entry in directory.listContents() {
if entry.name.extension == "mp3", entry.name.stem.contains("daisy") {
// Found it!
return entry.path
}
}
// No luck.
return nil
}
if let path = path {
print("Found file at '\(path)'")
}
// The file system can also be used to perform the following operations on files
// and directories:
// - copy,
// - remove,
// - rename, and
// - replace.
//
// The code above for reading the file is shorthand for opening the file in
// read-only mode and then reading its contents. The FileSystemProtocol
// has a few different 'withFileHandle' methods for opening a file in different
// modes. Let's open a file for writing, creating it at the same time.
try await fileSystem.withFileHandle(
forWritingAt: "/Users/hal9000/demise-of-dave.txt",
options: .newFile(replaceExisting: false)
) { file in
let plan = ByteBuffer(string: "TODO...")
try await file.write(contentsOf: plan.readableBytesView, toAbsoluteOffset: 0)
// Here's an example of copying a directory:
try await fileSystem.copyItem(at: "/Users/hal9000/Music", to: "/Volumes/Tardis/Music")
// Symbolic links can also be created (and read with 'destinationOfSymbolicLink(at:)').
try await fileSystem.createSymbolicLink(at: "/Users/hal9000/Backup", withDestination: "/Volumes/Tardis")
// Opening a symbolic link opens its destination so in most cases there's no
// need to read the destination of a symbolic link:
try await fileSystem.withDirectoryHandle(atPath: "/Users/hal9000/Backup") { directory in
// Beyond listing the contents of a directory, the directory handle provides a
// number of other functions, many of which are also available on regular file
// handles.
//
// This includes getting information about a file, such as its permissions, last access time,
// and last modification time:
let info = try await directory.info()
print("The directory has permissions '\(info.permissions)'")
// Where supported, the extended attributes of a file can also be accessed, read, and modified:
for attribute in try await directory.attributeNames() {
let value = try await directory.valueForAttribute(attribute)
print("Extended attribute '\(attribute)' has value '\(value)'")
}
// Once this closure returns the file system will close the directory handle freeing
// any resources required to access it such as file descriptors. Handles can also be opened
// with the 'openFile' and 'openDirectory' APIs but that places the onus you to close the
// handle at an appropriate time to avoid leaking resources.
}
}
// Directories can be opened like regular files but they cannot be read from or
// written to. However, their contents can be listed:
let path: FilePath? = try await fileSystem.withDirectoryHandle(atPath: "/Users/hal9000/Music") { directory in
for try await entry in directory.listContents() {
if entry.name.extension == "mp3", entry.name.stem.contains("daisy") {
// Found it!
return entry.path
}
}
// No luck.
return nil
}
if let path = path {
print("Found file at '\(path)'")
}
// The file system can also be used to perform the following operations on files
// and directories:
// - copy,
// - remove,
// - rename, and
// - replace.
//
// Here's an example of copying a directory:
try await fileSystem.copyItem(at: "/Users/hal9000/Music", to: "/Volumes/Tardis/Music")
// Symbolic links can also be created (and read with 'destinationOfSymbolicLink(at:)').
try await fileSystem.createSymbolicLink(at: "/Users/hal9000/Backup", withDestination: "/Volumes/Tardis")
// Opening a symbolic link opens its destination so in most cases there's no
// need to read the destination of a symbolic link:
try await fileSystem.withDirectoryHandle(atPath: "/Users/hal9000/Backup") { directory in
// Beyond listing the contents of a directory, the directory handle provides a
// number of other functions, many of which are also available on regular file
// handles.
//
// This includes getting information about a file, such as its permissions, last access time,
// and last modification time:
let info = try await directory.info()
print("The directory has permissions '\(info.permissions)'")
// Where supported, the extended attributes of a file can also be accessed, read, and modified:
for attribute in try await directory.attributeNames() {
let value = try await directory.valueForAttribute(attribute)
print("Extended attribute '\(attribute)' has value '\(value)'")
}
// Once this closure returns the file system will close the directory handle freeing
// any resources required to access it such as file descriptors. Handles can also be opened
// with the 'openFile' and 'openDirectory' APIs but that places the onus you to close the
// handle at an appropriate time to avoid leaking resources.
}
// snippet.end
// snippet.end
}
@@ -24,7 +24,8 @@ struct AsyncChannelIO<Request, Response> {
}
func start() async throws -> AsyncChannelIO<Request, Response> {
try await channel.pipeline.addHandler(RequestResponseHandler<HTTPRequestHead, NIOHTTPClientResponseFull>()).get()
try await channel.pipeline.addHandler(RequestResponseHandler<HTTPRequestHead, NIOHTTPClientResponseFull>())
.get()
return self
}
@@ -63,7 +63,6 @@ public final class RequestResponseHandler<Request, Response>: ChannelDuplexHandl
private var state: State = .operational
private var promiseBuffer: CircularBuffer<EventLoopPromise<Response>>
/// Create a new `RequestResponseHandler`.
///
/// - parameters:
@@ -83,7 +82,7 @@ public final class RequestResponseHandler<Request, Response>: ChannelDuplexHandl
case .operational:
let promiseBuffer = self.promiseBuffer
self.promiseBuffer.removeAll()
promiseBuffer.forEach { promise in
for promise in promiseBuffer {
promise.fail(ChannelError.eof)
}
}
@@ -112,8 +111,8 @@ public final class RequestResponseHandler<Request, Response>: ChannelDuplexHandl
let promiseBuffer = self.promiseBuffer
self.promiseBuffer.removeAll()
context.close(promise: nil)
promiseBuffer.forEach {
$0.fail(error)
for promise in promiseBuffer {
promise.fail(error)
}
}
+28 -13
View File
@@ -11,18 +11,25 @@
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import NIOCore
import NIOPosix
import NIOHTTP1
import Dispatch
import NIOCore
import NIOHTTP1
import NIOPosix
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
func makeHTTPChannel(host: String, port: Int, group: EventLoopGroup) async throws -> AsyncChannelIO<HTTPRequestHead, NIOHTTPClientResponseFull> {
func makeHTTPChannel(
host: String,
port: Int,
group: EventLoopGroup
) async throws -> AsyncChannelIO<HTTPRequestHead, NIOHTTPClientResponseFull> {
let channel = try await ClientBootstrap(group: group)
.channelInitializer { channel in
channel.eventLoop.makeCompletedFuture {
try channel.pipeline.syncOperations.addHTTPClientHandlers()
try channel.pipeline.syncOperations.addHandler(NIOHTTPClientResponseAggregator(maxContentLength: 1_000_000))
try channel.pipeline.syncOperations.addHandler(
NIOHTTPClientResponseAggregator(maxContentLength: 1_000_000)
)
try channel.pipeline.syncOperations.addHandler(MakeFullRequestHandler())
}
}
@@ -39,17 +46,25 @@ func main() async {
print("OK, connected to \(channel)")
print("Sending request 1", terminator: "")
let response1 = try await channel.sendRequest(HTTPRequestHead(version: .http1_1,
method: .GET,
uri: "/base64/SGVsbG8gV29ybGQsIGZyb20gSFRUUEJpbiEgCg==",
headers: ["host": "httpbin.org"]))
let response1 = try await channel.sendRequest(
HTTPRequestHead(
version: .http1_1,
method: .GET,
uri: "/base64/SGVsbG8gV29ybGQsIGZyb20gSFRUUEJpbiEgCg==",
headers: ["host": "httpbin.org"]
)
)
print(", response:", String(buffer: response1.body ?? ByteBuffer()))
print("Sending request 2", terminator: "")
let response2 = try await channel.sendRequest(HTTPRequestHead(version: .http1_1,
method: .GET,
uri: "/get",
headers: ["host": "httpbin.org"]))
let response2 = try await channel.sendRequest(
HTTPRequestHead(
version: .http1_1,
method: .GET,
uri: "/get",
headers: ["host": "httpbin.org"]
)
)
print(", response:", String(buffer: response2.body ?? ByteBuffer()))
try await channel.close()
+5 -5
View File
@@ -20,7 +20,7 @@ private final class ChatHandler: ChannelInboundHandler {
private func printByte(_ byte: UInt8) {
#if os(Android)
print(Character(UnicodeScalar(byte)), terminator:"")
print(Character(UnicodeScalar(byte)), terminator: "")
#else
fputc(Int32(byte), stdout)
#endif
@@ -68,14 +68,14 @@ enum ConnectTo {
let connectTarget: ConnectTo
switch (arg1, arg1.flatMap(Int.init), arg2.flatMap(Int.init)) {
case (.some(let h), _ , .some(let p)):
/* we got two arguments, let's interpret that as host and port */
case (.some(let h), _, .some(let p)):
// we got two arguments, let's interpret that as host and port
connectTarget = .ip(host: h, port: p)
case (.some(let portString), .none, _):
/* couldn't parse as number, expecting unix domain socket path */
// couldn't parse as number, expecting unix domain socket path
connectTarget = .unixDomainSocket(path: portString)
case (_, .some(let p), _):
/* only one argument --> port */
// only one argument --> port
connectTarget = .ip(host: defaultHost, port: p)
default:
connectTarget = .ip(host: defaultHost, port: defaultPort)
+25 -12
View File
@@ -11,9 +11,10 @@
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import Dispatch
import NIOCore
import NIOPosix
import Dispatch
private let newLine = "\n".utf8.first!
@@ -51,28 +52,36 @@ final class ChatHandler: ChannelInboundHandler {
// All access to channels is guarded by channelsSyncQueue.
private let channelsSyncQueue = DispatchQueue(label: "channelsQueue")
private var channels: [ObjectIdentifier: Channel] = [:]
public func channelActive(context: ChannelHandlerContext) {
let remoteAddress = context.remoteAddress!
let channel = context.channel
self.channelsSyncQueue.async {
// broadcast the message to all the connected clients except the one that just became active.
self.writeToAll(channels: self.channels, allocator: channel.allocator, message: "(ChatServer) - New client connected with address: \(remoteAddress)\n")
self.writeToAll(
channels: self.channels,
allocator: channel.allocator,
message: "(ChatServer) - New client connected with address: \(remoteAddress)\n"
)
self.channels[ObjectIdentifier(channel)] = channel
}
var buffer = channel.allocator.buffer(capacity: 64)
buffer.writeString("(ChatServer) - Welcome to: \(context.localAddress!)\n")
context.writeAndFlush(Self.wrapOutboundOut(buffer), promise: nil)
}
public func channelInactive(context: ChannelHandlerContext) {
let channel = context.channel
self.channelsSyncQueue.async {
if self.channels.removeValue(forKey: ObjectIdentifier(channel)) != nil {
// Broadcast the message to all the connected clients except the one that just was disconnected.
self.writeToAll(channels: self.channels, allocator: channel.allocator, message: "(ChatServer) - Client disconnected\n")
self.writeToAll(
channels: self.channels,
allocator: channel.allocator,
message: "(ChatServer) - Client disconnected\n"
)
}
}
}
@@ -100,12 +109,14 @@ final class ChatHandler: ChannelInboundHandler {
}
private func writeToAll(channels: [ObjectIdentifier: Channel], allocator: ByteBufferAllocator, message: String) {
let buffer = allocator.buffer(string: message)
let buffer = allocator.buffer(string: message)
self.writeToAll(channels: channels, buffer: buffer)
}
private func writeToAll(channels: [ObjectIdentifier: Channel], buffer: ByteBuffer) {
channels.forEach { $0.value.writeAndFlush(buffer, promise: nil) }
for channel in channels {
channel.value.writeAndFlush(buffer, promise: nil)
}
}
}
@@ -154,8 +165,8 @@ enum BindTo {
let bindTarget: BindTo
switch (arg1, arg1.flatMap(Int.init), arg2.flatMap(Int.init)) {
case (.some(let h), _ , .some(let p)):
/* we got two arguments, let's interpret that as host and port */
case (.some(let h), _, .some(let p)):
// we got two arguments, let's interpret that as host and port
bindTarget = .ip(host: h, port: p)
case (let portString?, .none, _):
@@ -180,7 +191,9 @@ let channel = try { () -> Channel in
}()
guard let localAddress = channel.localAddress else {
fatalError("Address was unable to bind. Please check that the socket was not closed or that the address family was understood.")
fatalError(
"Address was unable to bind. Please check that the socket was not closed or that the address family was understood."
)
}
print("Server started and listening on \(localAddress)")
+108 -100
View File
@@ -33,145 +33,153 @@ public protocol NIOAtomicPrimitive {
extension Bool: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic__Bool
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic__Bool_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic__Bool_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic__Bool_add
public static let nio_atomic_sub = catmc_nio_atomic__Bool_sub
public static let nio_atomic_exchange = catmc_nio_atomic__Bool_exchange
public static let nio_atomic_load = catmc_nio_atomic__Bool_load
public static let nio_atomic_store = catmc_nio_atomic__Bool_store
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic__Bool_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic__Bool_add
public static let nio_atomic_sub = catmc_nio_atomic__Bool_sub
public static let nio_atomic_exchange = catmc_nio_atomic__Bool_exchange
public static let nio_atomic_load = catmc_nio_atomic__Bool_load
public static let nio_atomic_store = catmc_nio_atomic__Bool_store
}
extension Int8: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_int_least8_t
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_int_least8_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_int_least8_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_int_least8_t_add
public static let nio_atomic_sub = catmc_nio_atomic_int_least8_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_int_least8_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_int_least8_t_load
public static let nio_atomic_store = catmc_nio_atomic_int_least8_t_store
public static let nio_atomic_create_with_existing_storage =
catmc_nio_atomic_int_least8_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_int_least8_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_int_least8_t_add
public static let nio_atomic_sub = catmc_nio_atomic_int_least8_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_int_least8_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_int_least8_t_load
public static let nio_atomic_store = catmc_nio_atomic_int_least8_t_store
}
extension UInt8: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_uint_least8_t
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_uint_least8_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_uint_least8_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_uint_least8_t_add
public static let nio_atomic_sub = catmc_nio_atomic_uint_least8_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_uint_least8_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_uint_least8_t_load
public static let nio_atomic_store = catmc_nio_atomic_uint_least8_t_store
public static let nio_atomic_create_with_existing_storage =
catmc_nio_atomic_uint_least8_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_uint_least8_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_uint_least8_t_add
public static let nio_atomic_sub = catmc_nio_atomic_uint_least8_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_uint_least8_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_uint_least8_t_load
public static let nio_atomic_store = catmc_nio_atomic_uint_least8_t_store
}
extension Int16: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_int_least16_t
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_int_least16_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_int_least16_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_int_least16_t_add
public static let nio_atomic_sub = catmc_nio_atomic_int_least16_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_int_least16_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_int_least16_t_load
public static let nio_atomic_store = catmc_nio_atomic_int_least16_t_store
public static let nio_atomic_create_with_existing_storage =
catmc_nio_atomic_int_least16_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_int_least16_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_int_least16_t_add
public static let nio_atomic_sub = catmc_nio_atomic_int_least16_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_int_least16_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_int_least16_t_load
public static let nio_atomic_store = catmc_nio_atomic_int_least16_t_store
}
extension UInt16: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_uint_least16_t
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_uint_least16_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_uint_least16_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_uint_least16_t_add
public static let nio_atomic_sub = catmc_nio_atomic_uint_least16_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_uint_least16_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_uint_least16_t_load
public static let nio_atomic_store = catmc_nio_atomic_uint_least16_t_store
public static let nio_atomic_create_with_existing_storage =
catmc_nio_atomic_uint_least16_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_uint_least16_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_uint_least16_t_add
public static let nio_atomic_sub = catmc_nio_atomic_uint_least16_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_uint_least16_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_uint_least16_t_load
public static let nio_atomic_store = catmc_nio_atomic_uint_least16_t_store
}
extension Int32: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_int_least32_t
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_int_least32_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_int_least32_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_int_least32_t_add
public static let nio_atomic_sub = catmc_nio_atomic_int_least32_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_int_least32_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_int_least32_t_load
public static let nio_atomic_store = catmc_nio_atomic_int_least32_t_store
public static let nio_atomic_create_with_existing_storage =
catmc_nio_atomic_int_least32_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_int_least32_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_int_least32_t_add
public static let nio_atomic_sub = catmc_nio_atomic_int_least32_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_int_least32_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_int_least32_t_load
public static let nio_atomic_store = catmc_nio_atomic_int_least32_t_store
}
extension UInt32: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_uint_least32_t
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_uint_least32_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_uint_least32_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_uint_least32_t_add
public static let nio_atomic_sub = catmc_nio_atomic_uint_least32_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_uint_least32_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_uint_least32_t_load
public static let nio_atomic_store = catmc_nio_atomic_uint_least32_t_store
public static let nio_atomic_create_with_existing_storage =
catmc_nio_atomic_uint_least32_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_uint_least32_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_uint_least32_t_add
public static let nio_atomic_sub = catmc_nio_atomic_uint_least32_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_uint_least32_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_uint_least32_t_load
public static let nio_atomic_store = catmc_nio_atomic_uint_least32_t_store
}
extension Int64: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_long_long
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_long_long_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_long_long_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_long_long_add
public static let nio_atomic_sub = catmc_nio_atomic_long_long_sub
public static let nio_atomic_exchange = catmc_nio_atomic_long_long_exchange
public static let nio_atomic_load = catmc_nio_atomic_long_long_load
public static let nio_atomic_store = catmc_nio_atomic_long_long_store
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_long_long_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_long_long_add
public static let nio_atomic_sub = catmc_nio_atomic_long_long_sub
public static let nio_atomic_exchange = catmc_nio_atomic_long_long_exchange
public static let nio_atomic_load = catmc_nio_atomic_long_long_load
public static let nio_atomic_store = catmc_nio_atomic_long_long_store
}
extension UInt64: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_unsigned_long_long
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_unsigned_long_long_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_unsigned_long_long_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_unsigned_long_long_add
public static let nio_atomic_sub = catmc_nio_atomic_unsigned_long_long_sub
public static let nio_atomic_exchange = catmc_nio_atomic_unsigned_long_long_exchange
public static let nio_atomic_load = catmc_nio_atomic_unsigned_long_long_load
public static let nio_atomic_store = catmc_nio_atomic_unsigned_long_long_store
public static let nio_atomic_create_with_existing_storage =
catmc_nio_atomic_unsigned_long_long_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_unsigned_long_long_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_unsigned_long_long_add
public static let nio_atomic_sub = catmc_nio_atomic_unsigned_long_long_sub
public static let nio_atomic_exchange = catmc_nio_atomic_unsigned_long_long_exchange
public static let nio_atomic_load = catmc_nio_atomic_unsigned_long_long_load
public static let nio_atomic_store = catmc_nio_atomic_unsigned_long_long_store
}
#if os(Windows)
extension Int: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_intptr_t
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_intptr_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_intptr_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_intptr_t_add
public static let nio_atomic_sub = catmc_nio_atomic_intptr_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_intptr_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_intptr_t_load
public static let nio_atomic_store = catmc_nio_atomic_intptr_t_store
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_intptr_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_intptr_t_add
public static let nio_atomic_sub = catmc_nio_atomic_intptr_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_intptr_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_intptr_t_load
public static let nio_atomic_store = catmc_nio_atomic_intptr_t_store
}
extension UInt: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_uintptr_t
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_uintptr_t_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_uintptr_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_uintptr_t_add
public static let nio_atomic_sub = catmc_nio_atomic_uintptr_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_uintptr_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_uintptr_t_load
public static let nio_atomic_store = catmc_nio_atomic_uintptr_t_store
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_uintptr_t_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_uintptr_t_add
public static let nio_atomic_sub = catmc_nio_atomic_uintptr_t_sub
public static let nio_atomic_exchange = catmc_nio_atomic_uintptr_t_exchange
public static let nio_atomic_load = catmc_nio_atomic_uintptr_t_load
public static let nio_atomic_store = catmc_nio_atomic_uintptr_t_store
}
#else
extension Int: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_long
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_long_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_long_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_long_add
public static let nio_atomic_sub = catmc_nio_atomic_long_sub
public static let nio_atomic_exchange = catmc_nio_atomic_long_exchange
public static let nio_atomic_load = catmc_nio_atomic_long_load
public static let nio_atomic_store = catmc_nio_atomic_long_store
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_long_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_long_add
public static let nio_atomic_sub = catmc_nio_atomic_long_sub
public static let nio_atomic_exchange = catmc_nio_atomic_long_exchange
public static let nio_atomic_load = catmc_nio_atomic_long_load
public static let nio_atomic_store = catmc_nio_atomic_long_store
}
extension UInt: NIOAtomicPrimitive {
public typealias AtomicWrapper = catmc_nio_atomic_unsigned_long
public static let nio_atomic_create_with_existing_storage = catmc_nio_atomic_unsigned_long_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_unsigned_long_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_unsigned_long_add
public static let nio_atomic_sub = catmc_nio_atomic_unsigned_long_sub
public static let nio_atomic_exchange = catmc_nio_atomic_unsigned_long_exchange
public static let nio_atomic_load = catmc_nio_atomic_unsigned_long_load
public static let nio_atomic_store = catmc_nio_atomic_unsigned_long_store
public static let nio_atomic_create_with_existing_storage =
catmc_nio_atomic_unsigned_long_create_with_existing_storage
public static let nio_atomic_compare_and_exchange = catmc_nio_atomic_unsigned_long_compare_and_exchange
public static let nio_atomic_add = catmc_nio_atomic_unsigned_long_add
public static let nio_atomic_sub = catmc_nio_atomic_unsigned_long_sub
public static let nio_atomic_exchange = catmc_nio_atomic_unsigned_long_exchange
public static let nio_atomic_load = catmc_nio_atomic_unsigned_long_load
public static let nio_atomic_store = catmc_nio_atomic_unsigned_long_store
}
#endif
@@ -193,7 +201,7 @@ extension UInt: NIOAtomicPrimitive {
/// By necessity, all atomic values are references: after all, it makes no
/// sense to talk about managing an atomic value when each time it's modified
/// the thread that modified it gets a local copy!
@available(*, deprecated, message:"please use ManagedAtomic from https://github.com/apple/swift-atomics instead")
@available(*, deprecated, message: "please use ManagedAtomic from https://github.com/apple/swift-atomics instead")
public final class NIOAtomic<T: NIOAtomicPrimitive> {
@usableFromInline
typealias Manager = ManagedBufferPointer<Void, T.AtomicWrapper>
@@ -225,8 +233,8 @@ public final class NIOAtomic<T: NIOAtomicPrimitive> {
/// match the current value and so no exchange occurred.
@inlinable
public func compareAndExchange(expected: T, desired: T) -> Bool {
return Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
return T.nio_atomic_compare_and_exchange($0, expected, desired)
Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
T.nio_atomic_compare_and_exchange($0, expected, desired)
}
}
@@ -241,8 +249,8 @@ public final class NIOAtomic<T: NIOAtomicPrimitive> {
@inlinable
@discardableResult
public func add(_ rhs: T) -> T {
return Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
return T.nio_atomic_add($0, rhs)
Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
T.nio_atomic_add($0, rhs)
}
}
@@ -257,8 +265,8 @@ public final class NIOAtomic<T: NIOAtomicPrimitive> {
@inlinable
@discardableResult
public func sub(_ rhs: T) -> T {
return Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
return T.nio_atomic_sub($0, rhs)
Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
T.nio_atomic_sub($0, rhs)
}
}
@@ -272,8 +280,8 @@ public final class NIOAtomic<T: NIOAtomicPrimitive> {
/// - Returns: The value previously held by this object.
@inlinable
public func exchange(with value: T) -> T {
return Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
return T.nio_atomic_exchange($0, value)
Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
T.nio_atomic_exchange($0, value)
}
}
@@ -286,8 +294,8 @@ public final class NIOAtomic<T: NIOAtomicPrimitive> {
/// - Returns: The value of this object
@inlinable
public func load() -> T {
return Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
return T.nio_atomic_load($0)
Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
T.nio_atomic_load($0)
}
}
@@ -299,9 +307,9 @@ public final class NIOAtomic<T: NIOAtomicPrimitive> {
///
/// - Parameter value: The new value to set the object to.
@inlinable
public func store(_ value: T) -> Void {
return Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
return T.nio_atomic_store($0, value)
public func store(_ value: T) {
Manager(unsafeBufferObject: self).withUnsafeMutablePointerToElements {
T.nio_atomic_store($0, value)
}
}
+31 -31
View File
@@ -34,61 +34,61 @@ typealias LockPrimitive = pthread_mutex_t
#endif
@usableFromInline
enum LockOperations { }
enum LockOperations {}
extension LockOperations {
@inlinable
static func create(_ mutex: UnsafeMutablePointer<LockPrimitive>) {
mutex.assertValidAlignment()
#if os(Windows)
#if os(Windows)
InitializeSRWLock(mutex)
#else
#else
var attr = pthread_mutexattr_t()
pthread_mutexattr_init(&attr)
debugOnly {
pthread_mutexattr_settype(&attr, .init(PTHREAD_MUTEX_ERRORCHECK))
}
let err = pthread_mutex_init(mutex, &attr)
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
#endif
#endif
}
@inlinable
static func destroy(_ mutex: UnsafeMutablePointer<LockPrimitive>) {
mutex.assertValidAlignment()
#if os(Windows)
#if os(Windows)
// SRWLOCK does not need to be free'd
#else
#else
let err = pthread_mutex_destroy(mutex)
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
#endif
#endif
}
@inlinable
static func lock(_ mutex: UnsafeMutablePointer<LockPrimitive>) {
mutex.assertValidAlignment()
#if os(Windows)
#if os(Windows)
AcquireSRWLockExclusive(mutex)
#else
#else
let err = pthread_mutex_lock(mutex)
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
#endif
#endif
}
@inlinable
static func unlock(_ mutex: UnsafeMutablePointer<LockPrimitive>) {
mutex.assertValidAlignment()
#if os(Windows)
#if os(Windows)
ReleaseSRWLockExclusive(mutex)
#else
#else
let err = pthread_mutex_unlock(mutex)
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
#endif
#endif
}
}
@@ -122,49 +122,49 @@ extension LockOperations {
// See also: https://github.com/apple/swift/pull/40000
@usableFromInline
final class LockStorage<Value>: ManagedBuffer<Value, LockPrimitive> {
@inlinable
static func create(value: Value) -> Self {
let buffer = Self.create(minimumCapacity: 1) { _ in
return value
value
}
let storage = unsafeDowncast(buffer, to: Self.self)
storage.withUnsafeMutablePointers { _, lockPtr in
LockOperations.create(lockPtr)
}
return storage
}
@inlinable
func lock() {
self.withUnsafeMutablePointerToElements { lockPtr in
LockOperations.lock(lockPtr)
}
}
@inlinable
func unlock() {
self.withUnsafeMutablePointerToElements { lockPtr in
LockOperations.unlock(lockPtr)
}
}
@inlinable
deinit {
self.withUnsafeMutablePointerToElements { lockPtr in
LockOperations.destroy(lockPtr)
}
}
@inlinable
func withLockPrimitive<T>(_ body: (UnsafeMutablePointer<LockPrimitive>) throws -> T) rethrows -> T {
try self.withUnsafeMutablePointerToElements { lockPtr in
return try body(lockPtr)
try body(lockPtr)
}
}
@inlinable
func withLockedValue<T>(_ mutate: (inout Value) throws -> T) rethrows -> T {
try self.withUnsafeMutablePointers { valuePtr, lockPtr in
@@ -175,7 +175,7 @@ final class LockStorage<Value>: ManagedBuffer<Value, LockPrimitive> {
}
}
extension LockStorage: @unchecked Sendable { }
extension LockStorage: @unchecked Sendable {}
/// A threading lock based on `libpthread` instead of `libdispatch`.
///
@@ -188,7 +188,7 @@ extension LockStorage: @unchecked Sendable { }
public struct NIOLock {
@usableFromInline
internal let _storage: LockStorage<Void>
/// Create a new lock.
@inlinable
public init() {
@@ -215,7 +215,7 @@ public struct NIOLock {
@inlinable
internal func withLockPrimitive<T>(_ body: (UnsafeMutablePointer<LockPrimitive>) throws -> T) rethrows -> T {
return try self._storage.withLockPrimitive(body)
try self._storage.withLockPrimitive(body)
}
}
@@ -238,7 +238,7 @@ extension NIOLock {
}
@inlinable
public func withLockVoid(_ body: () throws -> Void) rethrows -> Void {
public func withLockVoid(_ body: () throws -> Void) rethrows {
try self.withLock(body)
}
}
@@ -22,7 +22,7 @@
/// acquire/release the lock in the correct place. ``NIOLockedValueBox`` makes
/// that much easier.
public struct NIOLockedValueBox<Value> {
@usableFromInline
internal let _storage: LockStorage<Value>
@@ -35,7 +35,7 @@ public struct NIOLockedValueBox<Value> {
/// Access the `Value`, allowing mutation of it.
@inlinable
public func withLockedValue<T>(_ mutate: (inout Value) throws -> T) rethrows -> T {
return try self._storage.withLockedValue(mutate)
try self._storage.withLockedValue(mutate)
}
/// Provides an unsafe view over the lock and its value.
@@ -72,7 +72,7 @@ public struct NIOLockedValueBox<Value> {
public func withValueAssumingLockIsAcquired<Result>(
_ mutate: (_ value: inout Value) throws -> Result
) rethrows -> Result {
return try self._storage.withUnsafeMutablePointerToHeader { value in
try self._storage.withUnsafeMutablePointerToHeader { value in
try mutate(&value.pointee)
}
}
+116 -112
View File
@@ -16,14 +16,14 @@ import CNIOAtomics
#if canImport(Darwin)
import Darwin
fileprivate func sys_sched_yield() {
private func sys_sched_yield() {
pthread_yield_np()
}
#elseif os(Windows)
import ucrt
import WinSDK
fileprivate func sys_sched_yield() {
Sleep(0)
private func sys_sched_yield() {
Sleep(0)
}
#else
#if canImport(Glibc)
@@ -34,7 +34,7 @@ import Musl
#error("The concurrency atomics module was unable to identify your C library.")
#endif
fileprivate func sys_sched_yield() {
private func sys_sched_yield() {
_ = sched_yield()
}
#endif
@@ -86,7 +86,7 @@ public struct UnsafeEmbeddedAtomic<T: AtomicPrimitive> {
/// match the current value and so no exchange occurred.
@inlinable
public func compareAndExchange(expected: T, desired: T) -> Bool {
return T.atomic_compare_and_exchange(self.value, expected, desired)
T.atomic_compare_and_exchange(self.value, expected, desired)
}
/// Atomically adds `rhs` to this object.
@@ -100,7 +100,7 @@ public struct UnsafeEmbeddedAtomic<T: AtomicPrimitive> {
@discardableResult
@inlinable
public func add(_ rhs: T) -> T {
return T.atomic_add(self.value, rhs)
T.atomic_add(self.value, rhs)
}
/// Atomically subtracts `rhs` from this object.
@@ -114,7 +114,7 @@ public struct UnsafeEmbeddedAtomic<T: AtomicPrimitive> {
@discardableResult
@inlinable
public func sub(_ rhs: T) -> T {
return T.atomic_sub(self.value, rhs)
T.atomic_sub(self.value, rhs)
}
/// Atomically exchanges `value` for the current value of this object.
@@ -127,7 +127,7 @@ public struct UnsafeEmbeddedAtomic<T: AtomicPrimitive> {
/// - Returns: The value previously held by this object.
@inlinable
public func exchange(with value: T) -> T {
return T.atomic_exchange(self.value, value)
T.atomic_exchange(self.value, value)
}
/// Atomically loads and returns the value of this object.
@@ -139,7 +139,7 @@ public struct UnsafeEmbeddedAtomic<T: AtomicPrimitive> {
/// - Returns: The value of this object
@inlinable
public func load() -> T {
return T.atomic_load(self.value)
T.atomic_load(self.value)
}
/// Atomically replaces the value of this object with `value`.
@@ -150,7 +150,7 @@ public struct UnsafeEmbeddedAtomic<T: AtomicPrimitive> {
///
/// - Parameter value: The new value to set the object to.
@inlinable
public func store(_ value: T) -> Void {
public func store(_ value: T) {
T.atomic_store(self.value, value)
}
@@ -181,7 +181,7 @@ public struct UnsafeEmbeddedAtomic<T: AtomicPrimitive> {
/// By necessity, all atomic values are references: after all, it makes no
/// sense to talk about managing an atomic value when each time it's modified
/// the thread that modified it gets a local copy!
@available(*, deprecated, message:"please use ManagedAtomic from https://github.com/apple/swift-atomics instead")
@available(*, deprecated, message: "please use ManagedAtomic from https://github.com/apple/swift-atomics instead")
public final class Atomic<T: AtomicPrimitive> {
@usableFromInline
internal let embedded: UnsafeEmbeddedAtomic<T>
@@ -209,7 +209,7 @@ public final class Atomic<T: AtomicPrimitive> {
/// match the current value and so no exchange occurred.
@inlinable
public func compareAndExchange(expected: T, desired: T) -> Bool {
return self.embedded.compareAndExchange(expected: expected, desired: desired)
self.embedded.compareAndExchange(expected: expected, desired: desired)
}
/// Atomically adds `rhs` to this object.
@@ -223,7 +223,7 @@ public final class Atomic<T: AtomicPrimitive> {
@discardableResult
@inlinable
public func add(_ rhs: T) -> T {
return self.embedded.add(rhs)
self.embedded.add(rhs)
}
/// Atomically subtracts `rhs` from this object.
@@ -237,7 +237,7 @@ public final class Atomic<T: AtomicPrimitive> {
@discardableResult
@inlinable
public func sub(_ rhs: T) -> T {
return self.embedded.sub(rhs)
self.embedded.sub(rhs)
}
/// Atomically exchanges `value` for the current value of this object.
@@ -250,7 +250,7 @@ public final class Atomic<T: AtomicPrimitive> {
/// - Returns: The value previously held by this object.
@inlinable
public func exchange(with value: T) -> T {
return self.embedded.exchange(with: value)
self.embedded.exchange(with: value)
}
/// Atomically loads and returns the value of this object.
@@ -262,7 +262,7 @@ public final class Atomic<T: AtomicPrimitive> {
/// - Returns: The value of this object
@inlinable
public func load() -> T {
return self.embedded.load()
self.embedded.load()
}
/// Atomically replaces the value of this object with `value`.
@@ -273,7 +273,7 @@ public final class Atomic<T: AtomicPrimitive> {
///
/// - Parameter value: The new value to set the object to.
@inlinable
public func store(_ value: T) -> Void {
public func store(_ value: T) {
self.embedded.store(value)
}
@@ -299,147 +299,147 @@ public protocol AtomicPrimitive {
}
extension Bool: AtomicPrimitive {
public static let atomic_create = catmc_atomic__Bool_create
public static let atomic_destroy = catmc_atomic__Bool_destroy
public static let atomic_create = catmc_atomic__Bool_create
public static let atomic_destroy = catmc_atomic__Bool_destroy
public static let atomic_compare_and_exchange = catmc_atomic__Bool_compare_and_exchange
public static let atomic_add = catmc_atomic__Bool_add
public static let atomic_sub = catmc_atomic__Bool_sub
public static let atomic_exchange = catmc_atomic__Bool_exchange
public static let atomic_load = catmc_atomic__Bool_load
public static let atomic_store = catmc_atomic__Bool_store
public static let atomic_add = catmc_atomic__Bool_add
public static let atomic_sub = catmc_atomic__Bool_sub
public static let atomic_exchange = catmc_atomic__Bool_exchange
public static let atomic_load = catmc_atomic__Bool_load
public static let atomic_store = catmc_atomic__Bool_store
}
extension Int8: AtomicPrimitive {
public static let atomic_create = catmc_atomic_int_least8_t_create
public static let atomic_destroy = catmc_atomic_int_least8_t_destroy
public static let atomic_create = catmc_atomic_int_least8_t_create
public static let atomic_destroy = catmc_atomic_int_least8_t_destroy
public static let atomic_compare_and_exchange = catmc_atomic_int_least8_t_compare_and_exchange
public static let atomic_add = catmc_atomic_int_least8_t_add
public static let atomic_sub = catmc_atomic_int_least8_t_sub
public static let atomic_exchange = catmc_atomic_int_least8_t_exchange
public static let atomic_load = catmc_atomic_int_least8_t_load
public static let atomic_store = catmc_atomic_int_least8_t_store
public static let atomic_add = catmc_atomic_int_least8_t_add
public static let atomic_sub = catmc_atomic_int_least8_t_sub
public static let atomic_exchange = catmc_atomic_int_least8_t_exchange
public static let atomic_load = catmc_atomic_int_least8_t_load
public static let atomic_store = catmc_atomic_int_least8_t_store
}
extension UInt8: AtomicPrimitive {
public static let atomic_create = catmc_atomic_uint_least8_t_create
public static let atomic_destroy = catmc_atomic_uint_least8_t_destroy
public static let atomic_create = catmc_atomic_uint_least8_t_create
public static let atomic_destroy = catmc_atomic_uint_least8_t_destroy
public static let atomic_compare_and_exchange = catmc_atomic_uint_least8_t_compare_and_exchange
public static let atomic_add = catmc_atomic_uint_least8_t_add
public static let atomic_sub = catmc_atomic_uint_least8_t_sub
public static let atomic_exchange = catmc_atomic_uint_least8_t_exchange
public static let atomic_load = catmc_atomic_uint_least8_t_load
public static let atomic_store = catmc_atomic_uint_least8_t_store
public static let atomic_add = catmc_atomic_uint_least8_t_add
public static let atomic_sub = catmc_atomic_uint_least8_t_sub
public static let atomic_exchange = catmc_atomic_uint_least8_t_exchange
public static let atomic_load = catmc_atomic_uint_least8_t_load
public static let atomic_store = catmc_atomic_uint_least8_t_store
}
extension Int16: AtomicPrimitive {
public static let atomic_create = catmc_atomic_int_least16_t_create
public static let atomic_destroy = catmc_atomic_int_least16_t_destroy
public static let atomic_create = catmc_atomic_int_least16_t_create
public static let atomic_destroy = catmc_atomic_int_least16_t_destroy
public static let atomic_compare_and_exchange = catmc_atomic_int_least16_t_compare_and_exchange
public static let atomic_add = catmc_atomic_int_least16_t_add
public static let atomic_sub = catmc_atomic_int_least16_t_sub
public static let atomic_exchange = catmc_atomic_int_least16_t_exchange
public static let atomic_load = catmc_atomic_int_least16_t_load
public static let atomic_store = catmc_atomic_int_least16_t_store
public static let atomic_add = catmc_atomic_int_least16_t_add
public static let atomic_sub = catmc_atomic_int_least16_t_sub
public static let atomic_exchange = catmc_atomic_int_least16_t_exchange
public static let atomic_load = catmc_atomic_int_least16_t_load
public static let atomic_store = catmc_atomic_int_least16_t_store
}
extension UInt16: AtomicPrimitive {
public static let atomic_create = catmc_atomic_uint_least16_t_create
public static let atomic_destroy = catmc_atomic_uint_least16_t_destroy
public static let atomic_create = catmc_atomic_uint_least16_t_create
public static let atomic_destroy = catmc_atomic_uint_least16_t_destroy
public static let atomic_compare_and_exchange = catmc_atomic_uint_least16_t_compare_and_exchange
public static let atomic_add = catmc_atomic_uint_least16_t_add
public static let atomic_sub = catmc_atomic_uint_least16_t_sub
public static let atomic_exchange = catmc_atomic_uint_least16_t_exchange
public static let atomic_load = catmc_atomic_uint_least16_t_load
public static let atomic_store = catmc_atomic_uint_least16_t_store
public static let atomic_add = catmc_atomic_uint_least16_t_add
public static let atomic_sub = catmc_atomic_uint_least16_t_sub
public static let atomic_exchange = catmc_atomic_uint_least16_t_exchange
public static let atomic_load = catmc_atomic_uint_least16_t_load
public static let atomic_store = catmc_atomic_uint_least16_t_store
}
extension Int32: AtomicPrimitive {
public static let atomic_create = catmc_atomic_int_least32_t_create
public static let atomic_destroy = catmc_atomic_int_least32_t_destroy
public static let atomic_create = catmc_atomic_int_least32_t_create
public static let atomic_destroy = catmc_atomic_int_least32_t_destroy
public static let atomic_compare_and_exchange = catmc_atomic_int_least32_t_compare_and_exchange
public static let atomic_add = catmc_atomic_int_least32_t_add
public static let atomic_sub = catmc_atomic_int_least32_t_sub
public static let atomic_exchange = catmc_atomic_int_least32_t_exchange
public static let atomic_load = catmc_atomic_int_least32_t_load
public static let atomic_store = catmc_atomic_int_least32_t_store
public static let atomic_add = catmc_atomic_int_least32_t_add
public static let atomic_sub = catmc_atomic_int_least32_t_sub
public static let atomic_exchange = catmc_atomic_int_least32_t_exchange
public static let atomic_load = catmc_atomic_int_least32_t_load
public static let atomic_store = catmc_atomic_int_least32_t_store
}
extension UInt32: AtomicPrimitive {
public static let atomic_create = catmc_atomic_uint_least32_t_create
public static let atomic_destroy = catmc_atomic_uint_least32_t_destroy
public static let atomic_create = catmc_atomic_uint_least32_t_create
public static let atomic_destroy = catmc_atomic_uint_least32_t_destroy
public static let atomic_compare_and_exchange = catmc_atomic_uint_least32_t_compare_and_exchange
public static let atomic_add = catmc_atomic_uint_least32_t_add
public static let atomic_sub = catmc_atomic_uint_least32_t_sub
public static let atomic_exchange = catmc_atomic_uint_least32_t_exchange
public static let atomic_load = catmc_atomic_uint_least32_t_load
public static let atomic_store = catmc_atomic_uint_least32_t_store
public static let atomic_add = catmc_atomic_uint_least32_t_add
public static let atomic_sub = catmc_atomic_uint_least32_t_sub
public static let atomic_exchange = catmc_atomic_uint_least32_t_exchange
public static let atomic_load = catmc_atomic_uint_least32_t_load
public static let atomic_store = catmc_atomic_uint_least32_t_store
}
extension Int64: AtomicPrimitive {
public static let atomic_create = catmc_atomic_long_long_create
public static let atomic_destroy = catmc_atomic_long_long_destroy
public static let atomic_create = catmc_atomic_long_long_create
public static let atomic_destroy = catmc_atomic_long_long_destroy
public static let atomic_compare_and_exchange = catmc_atomic_long_long_compare_and_exchange
public static let atomic_add = catmc_atomic_long_long_add
public static let atomic_sub = catmc_atomic_long_long_sub
public static let atomic_exchange = catmc_atomic_long_long_exchange
public static let atomic_load = catmc_atomic_long_long_load
public static let atomic_store = catmc_atomic_long_long_store
public static let atomic_add = catmc_atomic_long_long_add
public static let atomic_sub = catmc_atomic_long_long_sub
public static let atomic_exchange = catmc_atomic_long_long_exchange
public static let atomic_load = catmc_atomic_long_long_load
public static let atomic_store = catmc_atomic_long_long_store
}
extension UInt64: AtomicPrimitive {
public static let atomic_create = catmc_atomic_unsigned_long_long_create
public static let atomic_destroy = catmc_atomic_unsigned_long_long_destroy
public static let atomic_create = catmc_atomic_unsigned_long_long_create
public static let atomic_destroy = catmc_atomic_unsigned_long_long_destroy
public static let atomic_compare_and_exchange = catmc_atomic_unsigned_long_long_compare_and_exchange
public static let atomic_add = catmc_atomic_unsigned_long_long_add
public static let atomic_sub = catmc_atomic_unsigned_long_long_sub
public static let atomic_exchange = catmc_atomic_unsigned_long_long_exchange
public static let atomic_load = catmc_atomic_unsigned_long_long_load
public static let atomic_store = catmc_atomic_unsigned_long_long_store
public static let atomic_add = catmc_atomic_unsigned_long_long_add
public static let atomic_sub = catmc_atomic_unsigned_long_long_sub
public static let atomic_exchange = catmc_atomic_unsigned_long_long_exchange
public static let atomic_load = catmc_atomic_unsigned_long_long_load
public static let atomic_store = catmc_atomic_unsigned_long_long_store
}
#if os(Windows)
extension Int: AtomicPrimitive {
public static let atomic_create = catmc_atomic_intptr_t_create
public static let atomic_destroy = catmc_atomic_intptr_t_destroy
public static let atomic_create = catmc_atomic_intptr_t_create
public static let atomic_destroy = catmc_atomic_intptr_t_destroy
public static let atomic_compare_and_exchange = catmc_atomic_intptr_t_compare_and_exchange
public static let atomic_add = catmc_atomic_intptr_t_add
public static let atomic_sub = catmc_atomic_intptr_t_sub
public static let atomic_exchange = catmc_atomic_intptr_t_exchange
public static let atomic_load = catmc_atomic_intptr_t_load
public static let atomic_store = catmc_atomic_intptr_t_store
public static let atomic_add = catmc_atomic_intptr_t_add
public static let atomic_sub = catmc_atomic_intptr_t_sub
public static let atomic_exchange = catmc_atomic_intptr_t_exchange
public static let atomic_load = catmc_atomic_intptr_t_load
public static let atomic_store = catmc_atomic_intptr_t_store
}
extension UInt: AtomicPrimitive {
public static let atomic_create = catmc_atomic_uintptr_t_create
public static let atomic_destroy = catmc_atomic_uintptr_t_destroy
public static let atomic_create = catmc_atomic_uintptr_t_create
public static let atomic_destroy = catmc_atomic_uintptr_t_destroy
public static let atomic_compare_and_exchange = catmc_atomic_uintptr_t_compare_and_exchange
public static let atomic_add = catmc_atomic_uintptr_t_add
public static let atomic_sub = catmc_atomic_uintptr_t_sub
public static let atomic_exchange = catmc_atomic_uintptr_t_exchange
public static let atomic_load = catmc_atomic_uintptr_t_load
public static let atomic_store = catmc_atomic_uintptr_t_store
public static let atomic_add = catmc_atomic_uintptr_t_add
public static let atomic_sub = catmc_atomic_uintptr_t_sub
public static let atomic_exchange = catmc_atomic_uintptr_t_exchange
public static let atomic_load = catmc_atomic_uintptr_t_load
public static let atomic_store = catmc_atomic_uintptr_t_store
}
#else
extension Int: AtomicPrimitive {
public static let atomic_create = catmc_atomic_long_create
public static let atomic_destroy = catmc_atomic_long_destroy
public static let atomic_create = catmc_atomic_long_create
public static let atomic_destroy = catmc_atomic_long_destroy
public static let atomic_compare_and_exchange = catmc_atomic_long_compare_and_exchange
public static let atomic_add = catmc_atomic_long_add
public static let atomic_sub = catmc_atomic_long_sub
public static let atomic_exchange = catmc_atomic_long_exchange
public static let atomic_load = catmc_atomic_long_load
public static let atomic_store = catmc_atomic_long_store
public static let atomic_add = catmc_atomic_long_add
public static let atomic_sub = catmc_atomic_long_sub
public static let atomic_exchange = catmc_atomic_long_exchange
public static let atomic_load = catmc_atomic_long_load
public static let atomic_store = catmc_atomic_long_store
}
extension UInt: AtomicPrimitive {
public static let atomic_create = catmc_atomic_unsigned_long_create
public static let atomic_destroy = catmc_atomic_unsigned_long_destroy
public static let atomic_create = catmc_atomic_unsigned_long_create
public static let atomic_destroy = catmc_atomic_unsigned_long_destroy
public static let atomic_compare_and_exchange = catmc_atomic_unsigned_long_compare_and_exchange
public static let atomic_add = catmc_atomic_unsigned_long_add
public static let atomic_sub = catmc_atomic_unsigned_long_sub
public static let atomic_exchange = catmc_atomic_unsigned_long_exchange
public static let atomic_load = catmc_atomic_unsigned_long_load
public static let atomic_store = catmc_atomic_unsigned_long_store
public static let atomic_add = catmc_atomic_unsigned_long_add
public static let atomic_sub = catmc_atomic_unsigned_long_sub
public static let atomic_exchange = catmc_atomic_unsigned_long_exchange
public static let atomic_load = catmc_atomic_unsigned_long_load
public static let atomic_store = catmc_atomic_unsigned_long_store
}
#endif
@@ -447,7 +447,11 @@ extension UInt: AtomicPrimitive {
///
/// - warning: The use of `AtomicBox` should be avoided because it requires an implementation of a spin-lock
/// (more precisely a CAS loop) to operate correctly.
@available(*, deprecated, message: "AtomicBox is deprecated without replacement because the original implementation doesn't work.")
@available(
*,
deprecated,
message: "AtomicBox is deprecated without replacement because the original implementation doesn't work."
)
public final class AtomicBox<T: AnyObject> {
private let storage: NIOAtomic<UInt>
@@ -482,7 +486,7 @@ public final class AtomicBox<T: AnyObject> {
/// - Returns: `True` if the exchange occurred, or `False` if `expected` did not
/// match the current value and so no exchange occurred.
public func compareAndExchange(expected: T, desired: T) -> Bool {
return withExtendedLifetime(desired) {
withExtendedLifetime(desired) {
let expectedPtr = Unmanaged<T>.passUnretained(expected)
let desiredPtr = Unmanaged<T>.passUnretained(desired)
let expectedPtrBits = UInt(bitPattern: expectedPtr.toOpaque())
@@ -573,7 +577,7 @@ public final class AtomicBox<T: AnyObject> {
// step 3: Now, let's exchange it back into the store
let casWorked = self.storage.compareAndExchange(expected: 0, desired: ptrBits)
precondition(casWorked) // this _has_ to work because `0` means we own it exclusively.
precondition(casWorked) // this _has_ to work because `0` means we own it exclusively.
return value
}
@@ -587,7 +591,7 @@ public final class AtomicBox<T: AnyObject> {
/// 100% CPU load.
///
/// - Parameter value: The new value to set the object to.
public func store(_ value: T) -> Void {
public func store(_ value: T) {
_ = self.exchange(with: value)
}
}
+53 -42
View File
@@ -33,19 +33,19 @@ import Musl
/// `SRWLOCK` type.
@available(*, deprecated, renamed: "NIOLock")
public final class Lock {
#if os(Windows)
#if os(Windows)
fileprivate let mutex: UnsafeMutablePointer<SRWLOCK> =
UnsafeMutablePointer.allocate(capacity: 1)
#else
#else
fileprivate let mutex: UnsafeMutablePointer<pthread_mutex_t> =
UnsafeMutablePointer.allocate(capacity: 1)
#endif
#endif
/// Create a new lock.
public init() {
#if os(Windows)
#if os(Windows)
InitializeSRWLock(self.mutex)
#else
#else
var attr = pthread_mutexattr_t()
pthread_mutexattr_init(&attr)
debugOnly {
@@ -54,16 +54,16 @@ public final class Lock {
let err = pthread_mutex_init(self.mutex, &attr)
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
#endif
#endif
}
deinit {
#if os(Windows)
#if os(Windows)
// SRWLOCK does not need to be free'd
#else
#else
let err = pthread_mutex_destroy(self.mutex)
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
#endif
#endif
mutex.deallocate()
}
@@ -72,12 +72,12 @@ public final class Lock {
/// Whenever possible, consider using `withLock` instead of this method and
/// `unlock`, to simplify lock handling.
public func lock() {
#if os(Windows)
#if os(Windows)
AcquireSRWLockExclusive(self.mutex)
#else
#else
let err = pthread_mutex_lock(self.mutex)
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
#endif
#endif
}
/// Release the lock.
@@ -85,12 +85,12 @@ public final class Lock {
/// Whenever possible, consider using `withLock` instead of this method and
/// `lock`, to simplify lock handling.
public func unlock() {
#if os(Windows)
#if os(Windows)
ReleaseSRWLockExclusive(self.mutex)
#else
#else
let err = pthread_mutex_unlock(self.mutex)
precondition(err == 0, "\(#function) failed in pthread_mutex with error \(err)")
#endif
#endif
}
/// Acquire the lock for the duration of the given block.
@@ -112,7 +112,7 @@ public final class Lock {
// specialise Void return (for performance)
@inlinable
public func withLockVoid(_ body: () throws -> Void) rethrows -> Void {
public func withLockVoid(_ body: () throws -> Void) rethrows {
try self.withLock(body)
}
}
@@ -124,13 +124,13 @@ public final class Lock {
public final class ConditionLock<T: Equatable> {
private var _value: T
private let mutex: NIOLock
#if os(Windows)
#if os(Windows)
private let cond: UnsafeMutablePointer<CONDITION_VARIABLE> =
UnsafeMutablePointer.allocate(capacity: 1)
#else
#else
private let cond: UnsafeMutablePointer<pthread_cond_t> =
UnsafeMutablePointer.allocate(capacity: 1)
#endif
#endif
/// Create the lock, and initialize the state variable to `value`.
///
@@ -138,21 +138,21 @@ public final class ConditionLock<T: Equatable> {
public init(value: T) {
self._value = value
self.mutex = NIOLock()
#if os(Windows)
#if os(Windows)
InitializeConditionVariable(self.cond)
#else
#else
let err = pthread_cond_init(self.cond, nil)
precondition(err == 0, "\(#function) failed in pthread_cond with error \(err)")
#endif
#endif
}
deinit {
#if os(Windows)
#if os(Windows)
// condition variables do not need to be explicitly destroyed
#else
#else
let err = pthread_cond_destroy(self.cond)
precondition(err == 0, "\(#function) failed in pthread_cond with error \(err)")
#endif
#endif
self.cond.deallocate()
}
@@ -190,13 +190,13 @@ public final class ConditionLock<T: Equatable> {
break
}
self.mutex.withLockPrimitive { mutex in
#if os(Windows)
#if os(Windows)
let result = SleepConditionVariableSRW(self.cond, mutex, INFINITE, 0)
precondition(result, "\(#function) failed in SleepConditionVariableSRW with error \(GetLastError())")
#else
#else
let err = pthread_cond_wait(self.cond, mutex)
precondition(err == 0, "\(#function) failed in pthread_cond with error \(err)")
#endif
#endif
}
}
}
@@ -212,7 +212,7 @@ public final class ConditionLock<T: Equatable> {
public func lock(whenValue wantedValue: T, timeoutSeconds: Double) -> Bool {
precondition(timeoutSeconds >= 0)
#if os(Windows)
#if os(Windows)
var dwMilliseconds: DWORD = DWORD(timeoutSeconds * 1000)
self.lock()
@@ -222,10 +222,14 @@ public final class ConditionLock<T: Equatable> {
}
let dwWaitStart = timeGetTime()
if !SleepConditionVariableSRW(self.cond, self.mutex._storage.mutex,
dwMilliseconds, 0) {
if !SleepConditionVariableSRW(
self.cond,
self.mutex._storage.mutex,
dwMilliseconds,
0
) {
let dwError = GetLastError()
if (dwError == ERROR_TIMEOUT) {
if dwError == ERROR_TIMEOUT {
self.unlock()
return false
}
@@ -235,18 +239,20 @@ public final class ConditionLock<T: Equatable> {
// NOTE: this may be a spurious wakeup, adjust the timeout accordingly
dwMilliseconds = dwMilliseconds - (timeGetTime() - dwWaitStart)
}
#else
let nsecPerSec: Int64 = 1000000000
#else
let nsecPerSec: Int64 = 1_000_000_000
self.lock()
/* the timeout as a (seconds, nano seconds) pair */
// the timeout as a (seconds, nano seconds) pair
let timeoutNS = Int64(timeoutSeconds * Double(nsecPerSec))
var curTime = timeval()
gettimeofday(&curTime, nil)
let allNSecs: Int64 = timeoutNS + Int64(curTime.tv_usec) * 1000
var timeoutAbs = timespec(tv_sec: curTime.tv_sec + Int((allNSecs / nsecPerSec)),
tv_nsec: Int(allNSecs % nsecPerSec))
var timeoutAbs = timespec(
tv_sec: curTime.tv_sec + Int((allNSecs / nsecPerSec)),
tv_nsec: Int(allNSecs % nsecPerSec)
)
assert(timeoutAbs.tv_nsec >= 0 && timeoutAbs.tv_nsec < Int(nsecPerSec))
assert(timeoutAbs.tv_sec >= curTime.tv_sec)
return self.mutex.withLockPrimitive { mutex -> Bool in
@@ -265,7 +271,7 @@ public final class ConditionLock<T: Equatable> {
}
}
}
#endif
#endif
}
/// Release the lock, setting the state variable to `newValue`.
@@ -275,12 +281,12 @@ public final class ConditionLock<T: Equatable> {
public func unlock(withValue newValue: T) {
self._value = newValue
self.unlock()
#if os(Windows)
#if os(Windows)
WakeAllConditionVariable(self.cond)
#else
#else
let err = pthread_cond_broadcast(self.cond)
precondition(err == 0, "\(#function) failed in pthread_cond with error \(err)")
#endif
#endif
}
}
@@ -291,7 +297,12 @@ public final class ConditionLock<T: Equatable> {
/// https://forums.swift.org/t/support-debug-only-code/11037 for a discussion.
@inlinable
internal func debugOnly(_ body: () -> Void) {
assert({ body(); return true }())
assert(
{
body()
return true
}()
)
}
@available(*, deprecated)
+4 -4
View File
@@ -27,19 +27,19 @@ public struct AddressedEnvelope<DataType> {
self.remoteAddress = remoteAddress
self.data = data
}
public init(remoteAddress: SocketAddress, data: DataType, metadata: Metadata?) {
self.remoteAddress = remoteAddress
self.data = data
self.metadata = metadata
}
/// Any metadata associated with an `AddressedEnvelope`
public struct Metadata: Hashable, Sendable {
/// Details of any congestion state.
public var ecnState: NIOExplicitCongestionNotificationState
public var packetInfo: NIOPacketInfo?
public init(ecnState: NIOExplicitCongestionNotificationState) {
self.ecnState = ecnState
self.packetInfo = nil
@@ -54,7 +54,7 @@ public struct AddressedEnvelope<DataType> {
extension AddressedEnvelope: CustomStringConvertible {
public var description: String {
return "AddressedEnvelope { remoteAddress: \(self.remoteAddress), data: \(self.data) }"
"AddressedEnvelope { remoteAddress: \(self.remoteAddress), data: \(self.data) }"
}
}
+48 -25
View File
@@ -20,7 +20,7 @@ extension EventLoopFuture {
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
@inlinable
public func get() async throws -> Value {
return try await withUnsafeThrowingContinuation { (cont: UnsafeContinuation<UnsafeTransfer<Value>, Error>) in
try await withUnsafeThrowingContinuation { (cont: UnsafeContinuation<UnsafeTransfer<Value>, Error>) in
self.whenComplete { result in
switch result {
case .success(let value):
@@ -38,7 +38,7 @@ extension EventLoopGroup {
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
@inlinable
public func shutdownGracefully() async throws {
return try await withCheckedThrowingContinuation { cont in
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
self.shutdownGracefully { error in
if let error = error {
cont.resume(throwing: error)
@@ -97,7 +97,7 @@ extension Channel {
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
@inlinable
public func getOption<Option: ChannelOption>(_ option: Option) async throws -> Option.Value {
return try await self.getOption(option).get()
try await self.getOption(option).get()
}
}
@@ -162,9 +162,11 @@ extension ChannelOutboundInvoker {
extension ChannelPipeline {
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
@preconcurrency
public func addHandler(_ handler: ChannelHandler & Sendable,
name: String? = nil,
position: ChannelPipeline.Position = .last) async throws {
public func addHandler(
_ handler: ChannelHandler & Sendable,
name: String? = nil,
position: ChannelPipeline.Position = .last
) async throws {
try await self.addHandler(handler, name: name, position: position).get()
}
@@ -185,43 +187,62 @@ extension ChannelPipeline {
}
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
@available(*, deprecated, message: "ChannelHandlerContext is not Sendable and it is therefore not safe to be used outside of its EventLoop")
@available(
*,
deprecated,
message:
"ChannelHandlerContext is not Sendable and it is therefore not safe to be used outside of its EventLoop"
)
@preconcurrency
public func context(handler: ChannelHandler & Sendable) async throws -> ChannelHandlerContext {
return try await self.context(handler: handler).map { UnsafeTransfer($0) }.get().wrappedValue
try await self.context(handler: handler).map { UnsafeTransfer($0) }.get().wrappedValue
}
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
@available(*, deprecated, message: "ChannelHandlerContext is not Sendable and it is therefore not safe to be used outside of its EventLoop")
@available(
*,
deprecated,
message:
"ChannelHandlerContext is not Sendable and it is therefore not safe to be used outside of its EventLoop"
)
public func context(name: String) async throws -> ChannelHandlerContext {
return try await self.context(name: name).map { UnsafeTransfer($0) }.get().wrappedValue
try await self.context(name: name).map { UnsafeTransfer($0) }.get().wrappedValue
}
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
@available(*, deprecated, message: "ChannelHandlerContext is not Sendable and it is therefore not safe to be used outside of its EventLoop")
@available(
*,
deprecated,
message:
"ChannelHandlerContext is not Sendable and it is therefore not safe to be used outside of its EventLoop"
)
@inlinable
public func context<Handler: ChannelHandler>(handlerType: Handler.Type) async throws -> ChannelHandlerContext {
return try await self.context(handlerType: handlerType).map { UnsafeTransfer($0) }.get().wrappedValue
try await self.context(handlerType: handlerType).map { UnsafeTransfer($0) }.get().wrappedValue
}
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
@preconcurrency
public func addHandlers(_ handlers: [ChannelHandler & Sendable],
position: ChannelPipeline.Position = .last) async throws {
public func addHandlers(
_ handlers: [ChannelHandler & Sendable],
position: ChannelPipeline.Position = .last
) async throws {
try await self.addHandlers(handlers, position: position).map { UnsafeTransfer($0) }.get().wrappedValue
}
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
@preconcurrency
public func addHandlers(_ handlers: (ChannelHandler & Sendable)...,
position: ChannelPipeline.Position = .last) async throws {
public func addHandlers(
_ handlers: (ChannelHandler & Sendable)...,
position: ChannelPipeline.Position = .last
) async throws {
try await self.addHandlers(handlers, position: position)
}
}
public struct NIOTooManyBytesError: Error, Hashable {
public init() {}
}
public init() {}
}
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
extension AsyncSequence where Element: RandomAccessCollection, Element.Element == UInt8 {
@@ -246,7 +267,7 @@ extension AsyncSequence where Element: RandomAccessCollection, Element.Element =
accumulationBuffer.writeBytes(fragment)
}
}
/// Accumulates an `AsyncSequence` of `RandomAccessCollection`s into a single ``ByteBuffer``.
/// - Parameters:
/// - maxBytes: The maximum number of bytes this method is allowed to accumulate
@@ -289,7 +310,7 @@ extension AsyncSequence where Element == ByteBuffer {
accumulationBuffer.writeImmutableBuffer(fragment)
}
}
/// Accumulates an `AsyncSequence` of ``ByteBuffer``s into a single ``ByteBuffer``.
/// - Parameters:
/// - maxBytes: The maximum number of bytes this method is allowed to accumulate
@@ -309,7 +330,7 @@ extension AsyncSequence where Element == ByteBuffer {
guard head.readableBytes <= maxBytes else {
throw NIOTooManyBytesError()
}
let tail = AsyncSequenceFromIterator(iterator)
// it is guaranteed that
// `maxBytes >= 0 && head.readableBytes >= 0 && head.readableBytes <= maxBytes`
@@ -324,13 +345,13 @@ extension AsyncSequence where Element == ByteBuffer {
@usableFromInline
struct AsyncSequenceFromIterator<AsyncIterator: AsyncIteratorProtocol>: AsyncSequence {
@usableFromInline typealias Element = AsyncIterator.Element
@usableFromInline var iterator: AsyncIterator
@inlinable init(_ iterator: AsyncIterator) {
self.iterator = iterator
}
@inlinable func makeAsyncIterator() -> AsyncIterator {
self.iterator
}
@@ -339,7 +360,9 @@ struct AsyncSequenceFromIterator<AsyncIterator: AsyncIteratorProtocol>: AsyncSeq
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
extension EventLoop {
@inlinable
public func makeFutureWithTask<Return>(_ body: @Sendable @escaping () async throws -> Return) -> EventLoopFuture<Return> {
public func makeFutureWithTask<Return>(
_ body: @Sendable @escaping () async throws -> Return
) -> EventLoopFuture<Return> {
let promise = self.makePromise(of: Return.self)
promise.completeWithTask(body)
return promise.futureResult
+43 -17
View File
@@ -58,7 +58,10 @@ public struct NIOAsyncChannel<Inbound: Sendable, Outbound: Sendable>: Sendable {
/// - inboundType: The ``NIOAsyncChannel/inbound`` message's type.
/// - outboundType: The ``NIOAsyncChannel/outbound`` message's type.
public init(
backPressureStrategy: NIOAsyncSequenceProducerBackPressureStrategies.HighLowWatermark = .init(lowWatermark: 2, highWatermark: 10),
backPressureStrategy: NIOAsyncSequenceProducerBackPressureStrategies.HighLowWatermark = .init(
lowWatermark: 2,
highWatermark: 10
),
isOutboundHalfClosureEnabled: Bool = false,
inboundType: Inbound.Type = Inbound.self,
outboundType: Outbound.Type = Outbound.self
@@ -147,7 +150,12 @@ public struct NIOAsyncChannel<Inbound: Sendable, Outbound: Sendable>: Sendable {
/// - Parameters:
/// - channel: The ``Channel`` to wrap.
/// - configuration: The ``NIOAsyncChannel``s configuration.
@available(*, deprecated, renamed: "init(wrappingChannelSynchronously:configuration:)", message: "This method has been deprecated since it defaults to deinit based resource teardown")
@available(
*,
deprecated,
renamed: "init(wrappingChannelSynchronously:configuration:)",
message: "This method has been deprecated since it defaults to deinit based resource teardown"
)
@inlinable
public init(
synchronouslyWrapping channel: Channel,
@@ -173,7 +181,12 @@ public struct NIOAsyncChannel<Inbound: Sendable, Outbound: Sendable>: Sendable {
/// - channel: The ``Channel`` to wrap.
/// - configuration: The ``NIOAsyncChannel``s configuration.
@inlinable
@available(*, deprecated, renamed: "init(wrappingChannelSynchronously:configuration:)", message: "This method has been deprecated since it defaults to deinit based resource teardown")
@available(
*,
deprecated,
renamed: "init(wrappingChannelSynchronously:configuration:)",
message: "This method has been deprecated since it defaults to deinit based resource teardown"
)
public init(
synchronouslyWrapping channel: Channel,
configuration: Configuration = .init()
@@ -206,7 +219,11 @@ public struct NIOAsyncChannel<Inbound: Sendable, Outbound: Sendable>: Sendable {
///
/// - Important: This is not considered stable API and should not be used.
@inlinable
@available(*, deprecated, message: "This method has been deprecated since it defaults to deinit based resource teardown")
@available(
*,
deprecated,
message: "This method has been deprecated since it defaults to deinit based resource teardown"
)
public static func _wrapAsyncChannelWithTransformations(
synchronouslyWrapping channel: Channel,
backPressureStrategy: NIOAsyncSequenceProducerBackPressureStrategies.HighLowWatermark? = nil,
@@ -214,12 +231,14 @@ public struct NIOAsyncChannel<Inbound: Sendable, Outbound: Sendable>: Sendable {
channelReadTransformation: @Sendable @escaping (Channel) -> EventLoopFuture<Inbound>
) throws -> NIOAsyncChannel<Inbound, Outbound> where Outbound == Never {
channel.eventLoop.preconditionInEventLoop()
let (inboundStream, outboundWriter): (NIOAsyncChannelInboundStream<Inbound>, NIOAsyncChannelOutboundWriter<Outbound>) = try channel._syncAddAsyncHandlersWithTransformations(
backPressureStrategy: backPressureStrategy,
isOutboundHalfClosureEnabled: isOutboundHalfClosureEnabled,
closeOnDeinit: true,
channelReadTransformation: channelReadTransformation
)
let (inboundStream, outboundWriter):
(NIOAsyncChannelInboundStream<Inbound>, NIOAsyncChannelOutboundWriter<Outbound>) =
try channel._syncAddAsyncHandlersWithTransformations(
backPressureStrategy: backPressureStrategy,
isOutboundHalfClosureEnabled: isOutboundHalfClosureEnabled,
closeOnDeinit: true,
channelReadTransformation: channelReadTransformation
)
outboundWriter.finish()
@@ -242,12 +261,14 @@ public struct NIOAsyncChannel<Inbound: Sendable, Outbound: Sendable>: Sendable {
channelReadTransformation: @Sendable @escaping (Channel) -> EventLoopFuture<Inbound>
) throws -> NIOAsyncChannel<Inbound, Outbound> where Outbound == Never {
channel.eventLoop.preconditionInEventLoop()
let (inboundStream, outboundWriter): (NIOAsyncChannelInboundStream<Inbound>, NIOAsyncChannelOutboundWriter<Outbound>) = try channel._syncAddAsyncHandlersWithTransformations(
backPressureStrategy: backPressureStrategy,
isOutboundHalfClosureEnabled: isOutboundHalfClosureEnabled,
closeOnDeinit: false,
channelReadTransformation: channelReadTransformation
)
let (inboundStream, outboundWriter):
(NIOAsyncChannelInboundStream<Inbound>, NIOAsyncChannelOutboundWriter<Outbound>) =
try channel._syncAddAsyncHandlersWithTransformations(
backPressureStrategy: backPressureStrategy,
isOutboundHalfClosureEnabled: isOutboundHalfClosureEnabled,
closeOnDeinit: false,
channelReadTransformation: channelReadTransformation
)
outboundWriter.finish()
@@ -264,7 +285,8 @@ public struct NIOAsyncChannel<Inbound: Sendable, Outbound: Sendable>: Sendable {
///
/// - Parameter body: A closure that gets scoped access to the inbound and outbound.
public func executeThenClose<Result>(
_ body: (_ inbound: NIOAsyncChannelInboundStream<Inbound>, _ outbound: NIOAsyncChannelOutboundWriter<Outbound>) async throws -> Result
_ body: (_ inbound: NIOAsyncChannelInboundStream<Inbound>, _ outbound: NIOAsyncChannelOutboundWriter<Outbound>)
async throws -> Result
) async throws -> Result {
let result: Result
do {
@@ -290,7 +312,11 @@ public struct NIOAsyncChannel<Inbound: Sendable, Outbound: Sendable>: Sendable {
}
return result
}
}
// swift-format-ignore: AmbiguousTrailingClosureOverload
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
extension NIOAsyncChannel {
/// Provides scoped access to the inbound side of the underlying ``Channel``.
///
/// - Important: After this method returned the underlying ``Channel`` will be closed.
@@ -147,7 +147,6 @@ extension NIOAsyncChannelHandler: ChannelInboundHandler {
context.fireChannelInactive()
}
@inlinable
func userInboundEventTriggered(context: ChannelHandlerContext, event: Any) {
switch event {
@@ -298,7 +297,6 @@ extension NIOAsyncChannelHandler {
}
}
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
extension NIOAsyncChannelHandler {
@inlinable
@@ -341,7 +339,9 @@ struct NIOAsyncChannelHandlerProducerDelegate: @unchecked Sendable, NIOAsyncSequ
let _produceMore: () -> Void
@inlinable
init<InboundIn, ProducerElement, OutboundOut>(handler: NIOAsyncChannelHandler<InboundIn, ProducerElement, OutboundOut>) {
init<InboundIn, ProducerElement, OutboundOut>(
handler: NIOAsyncChannelHandler<InboundIn, ProducerElement, OutboundOut>
) {
self.eventLoop = handler.eventLoop
self._didTerminate = handler._didTerminate
self._produceMore = handler._produceMore
@@ -151,7 +151,7 @@ extension NIOAsyncChannelInboundStream: AsyncSequence {
@inlinable
public func makeAsyncIterator() -> AsyncIterator {
return AsyncIterator(self._backing)
AsyncIterator(self._backing)
}
}
@@ -144,7 +144,8 @@ public struct NIOAsyncChannelOutboundWriter<OutboundOut: Sendable>: Sendable {
///
/// This method suspends if the underlying channel is not writable and will resume once the it becomes writable again.
@inlinable
public func write<Writes: AsyncSequence>(contentsOf sequence: Writes) async throws where Writes.Element == OutboundOut {
public func write<Writes: AsyncSequence>(contentsOf sequence: Writes) async throws
where Writes.Element == OutboundOut {
for try await data in sequence {
try await self.write(data)
}
@@ -112,7 +112,7 @@ public struct NIOAsyncSequenceProducer<
public let sequence: NIOAsyncSequenceProducer
@usableFromInline
/* fileprivate */ internal init(
internal init(
source: Source,
sequence: NIOAsyncSequenceProducer
) {
@@ -122,12 +122,13 @@ public struct NIOAsyncSequenceProducer<
}
@usableFromInline
/* private */ internal let _throwingSequence: NIOThrowingAsyncSequenceProducer<
Element,
Never,
Strategy,
Delegate
>
internal let _throwingSequence:
NIOThrowingAsyncSequenceProducer<
Element,
Never,
Strategy,
Delegate
>
/// Initializes a new ``NIOAsyncSequenceProducer`` and a ``NIOAsyncSequenceProducer/Source``.
///
@@ -175,7 +176,12 @@ public struct NIOAsyncSequenceProducer<
/// - delegate: The delegate of the sequence
/// - Returns: A ``NIOAsyncSequenceProducer/Source`` and a ``NIOAsyncSequenceProducer``.
@inlinable
@available(*, deprecated, renamed: "makeSequence(elementType:backPressureStrategy:finishOnDeinit:delegate:)", message: "This method has been deprecated since it defaults to deinit based resource teardown")
@available(
*,
deprecated,
renamed: "makeSequence(elementType:backPressureStrategy:finishOnDeinit:delegate:)",
message: "This method has been deprecated since it defaults to deinit based resource teardown"
)
public static func makeSequence(
elementType: Element.Type = Element.self,
backPressureStrategy: Strategy,
@@ -194,7 +200,7 @@ public struct NIOAsyncSequenceProducer<
}
@inlinable
/* private */ internal init(
internal init(
throwingSequence: NIOThrowingAsyncSequenceProducer<Element, Never, Strategy, Delegate>
) {
self._throwingSequence = throwingSequence
@@ -212,12 +218,13 @@ extension NIOAsyncSequenceProducer: AsyncSequence {
extension NIOAsyncSequenceProducer {
public struct AsyncIterator: AsyncIteratorProtocol {
@usableFromInline
/* private */ internal let _throwingIterator: NIOThrowingAsyncSequenceProducer<
Element,
Never,
Strategy,
Delegate
>.AsyncIterator
internal let _throwingIterator:
NIOThrowingAsyncSequenceProducer<
Element,
Never,
Strategy,
Delegate
>.AsyncIterator
fileprivate init(
throwingIterator: NIOThrowingAsyncSequenceProducer<
@@ -233,7 +240,7 @@ extension NIOAsyncSequenceProducer {
@inlinable
public func next() async -> Element? {
// this call will only throw if cancelled and we want to just return nil in that case
return try? await self._throwingIterator.next()
try? await self._throwingIterator.next()
}
}
}
@@ -253,10 +260,10 @@ extension NIOAsyncSequenceProducer {
>.Source
@usableFromInline
/* private */ internal var _throwingSource: ThrowingSource
internal var _throwingSource: ThrowingSource
@usableFromInline
/* fileprivate */ internal init(throwingSource: ThrowingSource) {
internal init(throwingSource: ThrowingSource) {
self._throwingSource = throwingSource
}
@@ -96,7 +96,7 @@ public struct NIOAsyncWriterError: Error, Hashable, CustomStringConvertible {
@inlinable
public static func == (lhs: NIOAsyncWriterError, rhs: NIOAsyncWriterError) -> Bool {
return lhs._code == rhs._code
lhs._code == rhs._code
}
@inlinable
@@ -147,7 +147,7 @@ public struct NIOAsyncWriter<
public let writer: NIOAsyncWriter
@inlinable
/* fileprivate */ internal init(
internal init(
sink: Sink,
writer: NIOAsyncWriter
) {
@@ -158,7 +158,7 @@ public struct NIOAsyncWriter<
/// This class is needed to hook the deinit to observe once all references to the ``NIOAsyncWriter`` are dropped.
@usableFromInline
/* fileprivate */ internal final class InternalClass: Sendable {
internal final class InternalClass: Sendable {
@usableFromInline
internal let _storage: Storage
@@ -183,10 +183,10 @@ public struct NIOAsyncWriter<
}
@usableFromInline
/* private */ internal let _internalClass: InternalClass
internal let _internalClass: InternalClass
@inlinable
/* private */ internal var _storage: Storage {
internal var _storage: Storage {
self._internalClass._storage
}
@@ -203,7 +203,12 @@ public struct NIOAsyncWriter<
/// - delegate: The delegate of the writer.
/// - Returns: A ``NIOAsyncWriter/NewWriter``.
@inlinable
@available(*, deprecated, renamed: "makeWriter(elementType:isWritable:finishOnDeinit:delegate:)", message: "This method has been deprecated since it defaults to deinit based resource teardown")
@available(
*,
deprecated,
renamed: "makeWriter(elementType:isWritable:finishOnDeinit:delegate:)",
message: "This method has been deprecated since it defaults to deinit based resource teardown"
)
public static func makeWriter(
elementType: Element.Type = Element.self,
isWritable: Bool,
@@ -251,7 +256,7 @@ public struct NIOAsyncWriter<
}
@inlinable
/* private */ internal init(
internal init(
isWritable: Bool,
finishOnDeinit: Bool,
delegate: Delegate
@@ -337,9 +342,9 @@ extension NIOAsyncWriter {
public struct Sink {
/// This class is needed to hook the deinit to observe once all references to the ``NIOAsyncWriter/Sink`` are dropped.
@usableFromInline
/* fileprivate */ internal final class InternalClass: Sendable {
internal final class InternalClass: Sendable {
@usableFromInline
/* fileprivate */ internal let _storage: Storage
internal let _storage: Storage
@usableFromInline
internal let _finishOnDeinit: Bool
@@ -362,10 +367,10 @@ extension NIOAsyncWriter {
}
@usableFromInline
/* private */ internal let _internalClass: InternalClass
internal let _internalClass: InternalClass
@inlinable
/* private */ internal var _storage: Storage {
internal var _storage: Storage {
self._internalClass._storage
}
@@ -414,7 +419,7 @@ extension NIOAsyncWriter {
extension NIOAsyncWriter {
/// This is the underlying storage of the writer. The goal of this is to synchronize the access to all state.
@usableFromInline
/* fileprivate */ internal struct Storage: Sendable {
internal struct Storage: Sendable {
/// Internal type to generate unique yield IDs.
///
/// This type has reference semantics.
@@ -424,7 +429,7 @@ extension NIOAsyncWriter {
@usableFromInline
struct YieldID: Equatable, Sendable {
@usableFromInline
/* private */ internal var value: UInt64
internal var value: UInt64
@inlinable
init(value: UInt64) {
@@ -447,10 +452,10 @@ extension NIOAsyncWriter {
/// The counter used to assign an ID to all our yields.
@usableFromInline
/* private */ internal let _yieldIDGenerator = YieldIDGenerator()
internal let _yieldIDGenerator = YieldIDGenerator()
/// The state machine.
@usableFromInline
/* private */ internal let _state: NIOLockedValueBox<State>
internal let _state: NIOLockedValueBox<State>
@usableFromInline
struct State: Sendable {
@@ -485,7 +490,7 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal init(
internal init(
isWritable: Bool,
delegate: Delegate
) {
@@ -494,7 +499,7 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal func setWritability(to writability: Bool) {
internal func setWritability(to writability: Bool) {
// We must not resume the continuation while holding the lock
// because it can deadlock in combination with the underlying ulock
// in cases where we race with a cancellation handler
@@ -504,7 +509,9 @@ extension NIOAsyncWriter {
switch action {
case .resumeContinuations(let suspendedYields):
suspendedYields.forEach { $0.continuation.resume(returning: .retry) }
for yield in suspendedYields {
yield .continuation.resume(returning: .retry)
}
case .none:
return
@@ -512,7 +519,8 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal func yield<S: Sequence>(contentsOf sequence: S) async throws where S.Element == Element {
internal func yield<S: Sequence>(contentsOf sequence: S) async throws
where S.Element == Element {
let yieldID = self._yieldIDGenerator.generateUniqueYieldID()
while true {
switch try await self._yield(contentsOf: sequence, yieldID: yieldID) {
@@ -525,7 +533,10 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal func _yield<S: Sequence>(contentsOf sequence: S, yieldID: StateMachine.YieldID?) async throws -> StateMachine.YieldResult where S.Element == Element {
internal func _yield<S: Sequence>(
contentsOf sequence: S,
yieldID: StateMachine.YieldID?
) async throws -> StateMachine.YieldResult where S.Element == Element {
let yieldID = yieldID ?? self._yieldIDGenerator.generateUniqueYieldID()
return try await withTaskCancellationHandler {
@@ -550,7 +561,8 @@ extension NIOAsyncWriter {
throw error
case .suspendTask:
return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<StateMachine.YieldResult, Error>) in
return try await withCheckedThrowingContinuation {
(continuation: CheckedContinuation<StateMachine.YieldResult, Error>) in
let didSuspend = unsafe.withValueAssumingLockIsAcquired {
$0.stateMachine.yield(continuation: continuation, yieldID: yieldID)
return $0.didSuspend
@@ -579,7 +591,7 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal func yield(element: Element) async throws {
internal func yield(element: Element) async throws {
let yieldID = self._yieldIDGenerator.generateUniqueYieldID()
while true {
switch try await self._yield(element: element, yieldID: yieldID) {
@@ -592,7 +604,10 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal func _yield(element: Element, yieldID: StateMachine.YieldID?) async throws -> StateMachine.YieldResult {
internal func _yield(
element: Element,
yieldID: StateMachine.YieldID?
) async throws -> StateMachine.YieldResult {
let yieldID = yieldID ?? self._yieldIDGenerator.generateUniqueYieldID()
return try await withTaskCancellationHandler {
@@ -617,7 +632,8 @@ extension NIOAsyncWriter {
throw error
case .suspendTask:
return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<StateMachine.YieldResult, Error>) in
return try await withCheckedThrowingContinuation {
(continuation: CheckedContinuation<StateMachine.YieldResult, Error>) in
let didSuspend = unsafe.withValueAssumingLockIsAcquired {
$0.stateMachine.yield(continuation: continuation, yieldID: yieldID)
return $0.didSuspend
@@ -645,7 +661,7 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal func writerFinish(error: Error?) {
internal func writerFinish(error: Error?) {
// We must not resume the continuation while holding the lock
// because it can deadlock in combination with the underlying ulock
// in cases where we race with a cancellation handler
@@ -658,7 +674,9 @@ extension NIOAsyncWriter {
delegate.didTerminate(error: error)
case .resumeContinuations(let suspendedYields):
suspendedYields.forEach { $0.continuation.resume(returning: .retry) }
for yield in suspendedYields {
yield .continuation.resume(returning: .retry)
}
case .none:
break
@@ -666,7 +684,7 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal func sinkFinish(error: Error?) {
internal func sinkFinish(error: Error?) {
// We must not resume the continuation while holding the lock
// because it can deadlock in combination with the underlying ulock
// in cases where we race with a cancellation handler
@@ -676,23 +694,26 @@ extension NIOAsyncWriter {
switch action {
case .resumeContinuationsWithError(let suspendedYields, let error):
suspendedYields.forEach { $0.continuation.resume(throwing: error) }
for yield in suspendedYields {
yield .continuation.resume(throwing: error)
}
case .none:
break
}
}
@inlinable
/* fileprivate */ internal func unbufferQueuedEvents() {
while let action = self._state.withLockedValue({ $0.stateMachine.unbufferQueuedEvents()}) {
internal func unbufferQueuedEvents() {
while let action = self._state.withLockedValue({ $0.stateMachine.unbufferQueuedEvents() }) {
switch action {
case .callDidTerminate(let delegate, let error):
delegate.didTerminate(error: error)
case .resumeContinuations(let suspendedYields):
suspendedYields.forEach { $0.continuation.resume(returning: .retry) }
for yield in suspendedYields {
yield .continuation.resume(returning: .retry)
}
return
}
}
@@ -703,12 +724,12 @@ extension NIOAsyncWriter {
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
extension NIOAsyncWriter {
@usableFromInline
/* private */ internal struct StateMachine: Sendable {
internal struct StateMachine: Sendable {
@usableFromInline
typealias YieldID = Storage.YieldIDGenerator.YieldID
/// This is a small helper struct to encapsulate the two different values for a suspended yield.
@usableFromInline
/* private */ internal struct SuspendedYield: Sendable {
internal struct SuspendedYield: Sendable {
/// The yield's ID.
@usableFromInline
var yieldID: YieldID
@@ -725,7 +746,7 @@ extension NIOAsyncWriter {
}
/// The internal result of a yield.
@usableFromInline
/* private */ internal enum YieldResult {
internal enum YieldResult {
/// Indicates that the elements got yielded to the sink.
case yielded
/// Indicates that the yield should be retried.
@@ -734,7 +755,7 @@ extension NIOAsyncWriter {
/// The current state of our ``NIOAsyncWriter``.
@usableFromInline
/* private */ internal enum State: Sendable, CustomStringConvertible {
internal enum State: Sendable, CustomStringConvertible {
/// The initial state before either a call to ``NIOAsyncWriter/yield(contentsOf:)`` or
/// ``NIOAsyncWriter/finish(completion:)`` happened.
case initial(
@@ -778,9 +799,19 @@ extension NIOAsyncWriter {
case .initial(let isWritable, _):
return "initial(isWritable: \(isWritable))"
case .streaming(let isWritable, let inDelegateOutcall, let cancelledYields, let suspendedYields, _):
return "streaming(isWritable: \(isWritable), inDelegateOutcall: \(inDelegateOutcall), cancelledYields: \(cancelledYields.count), suspendedYields: \(suspendedYields.count))"
case .writerFinished(let isWritable, let inDelegateOutcall, let suspendedYields, let cancelledYields, let bufferedYieldIDs, _, _):
return "writerFinished(isWritable: \(isWritable), inDelegateOutcall: \(inDelegateOutcall), suspendedYields: \(suspendedYields.count), cancelledYields: \(cancelledYields.count), bufferedYieldIDs: \(bufferedYieldIDs.count)"
return
"streaming(isWritable: \(isWritable), inDelegateOutcall: \(inDelegateOutcall), cancelledYields: \(cancelledYields.count), suspendedYields: \(suspendedYields.count))"
case .writerFinished(
let isWritable,
let inDelegateOutcall,
let suspendedYields,
let cancelledYields,
let bufferedYieldIDs,
_,
_
):
return
"writerFinished(isWritable: \(isWritable), inDelegateOutcall: \(inDelegateOutcall), suspendedYields: \(suspendedYields.count), cancelledYields: \(cancelledYields.count), bufferedYieldIDs: \(bufferedYieldIDs.count)"
case .finished:
return "finished"
case .modifying:
@@ -791,7 +822,7 @@ extension NIOAsyncWriter {
/// The state machine's current state.
@usableFromInline
/* private */ internal var _state: State
internal var _state: State
@inlinable
internal var isWriterFinished: Bool {
@@ -817,7 +848,6 @@ extension NIOAsyncWriter {
}
}
@inlinable
init(
isWritable: Bool,
@@ -834,7 +864,7 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal mutating func setWritability(to newWritability: Bool) -> SetWritabilityAction? {
internal mutating func setWritability(to newWritability: Bool) -> SetWritabilityAction? {
switch self._state {
case .initial(_, let delegate):
// We just need to store the new writability state
@@ -842,7 +872,13 @@ extension NIOAsyncWriter {
return .none
case .streaming(let isWritable, let inDelegateOutcall, let cancelledYields, let suspendedYields, let delegate):
case .streaming(
let isWritable,
let inDelegateOutcall,
let cancelledYields,
let suspendedYields,
let delegate
):
if isWritable == newWritability {
// The writability didn't change so we can just early exit here
return .none
@@ -882,7 +918,15 @@ extension NIOAsyncWriter {
return .none
}
case .writerFinished(_, let inDelegateOutcall, let suspendedYields, let cancelledYields, let bufferedYieldIDs, let delegate, let error):
case .writerFinished(
_,
let inDelegateOutcall,
let suspendedYields,
let cancelledYields,
let bufferedYieldIDs,
let delegate,
let error
):
if !newWritability {
// We are not writable so we can't deliver the outstanding elements
return .none
@@ -958,7 +1002,7 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal mutating func yield(
internal mutating func yield(
yieldID: YieldID
) -> YieldAction {
switch self._state {
@@ -967,7 +1011,7 @@ extension NIOAsyncWriter {
self._state = .streaming(
isWritable: isWritable,
inDelegateOutcall: isWritable, // If we are writable we are going to make an outcall
inDelegateOutcall: isWritable, // If we are writable we are going to make an outcall
cancelledYields: [],
suspendedYields: .init(),
delegate: delegate
@@ -975,7 +1019,13 @@ extension NIOAsyncWriter {
return .init(isWritable: isWritable, delegate: delegate)
case .streaming(let isWritable, let inDelegateOutcall, var cancelledYields, let suspendedYields, let delegate):
case .streaming(
let isWritable,
let inDelegateOutcall,
var cancelledYields,
let suspendedYields,
let delegate
):
self._state = .modifying
if let index = cancelledYields.firstIndex(of: yieldID) {
@@ -999,7 +1049,7 @@ extension NIOAsyncWriter {
case (true, false):
self._state = .streaming(
isWritable: isWritable,
inDelegateOutcall: true, // We are now making a call to the delegate
inDelegateOutcall: true, // We are now making a call to the delegate
cancelledYields: cancelledYields,
suspendedYields: suspendedYields,
delegate: delegate
@@ -1018,7 +1068,15 @@ extension NIOAsyncWriter {
}
}
case .writerFinished(let isWritable, let inDelegateOutcall, let suspendedYields, var cancelledYields, let bufferedYieldIDs, let delegate, let error):
case .writerFinished(
let isWritable,
let inDelegateOutcall,
let suspendedYields,
var cancelledYields,
let bufferedYieldIDs,
let delegate,
let error
):
if bufferedYieldIDs.contains(yieldID) {
// This yield was buffered before we became finished so we still have to deliver it
self._state = .modifying
@@ -1046,7 +1104,7 @@ extension NIOAsyncWriter {
case (true, false):
self._state = .writerFinished(
isWritable: isWritable,
inDelegateOutcall: true, // We are now making a call to the delegate
inDelegateOutcall: true, // We are now making a call to the delegate
suspendedYields: suspendedYields,
cancelledYields: cancelledYields,
bufferedYieldIDs: bufferedYieldIDs,
@@ -1084,12 +1142,18 @@ extension NIOAsyncWriter {
/// This method is called as a result of the above `yield` method if it decided that the task needs to get suspended.
@inlinable
/* fileprivate */ internal mutating func yield(
internal mutating func yield(
continuation: CheckedContinuation<YieldResult, Error>,
yieldID: YieldID
) {
switch self._state {
case .streaming(let isWritable, let inDelegateOutcall, let cancelledYields, var suspendedYields, let delegate):
case .streaming(
let isWritable,
let inDelegateOutcall,
let cancelledYields,
var suspendedYields,
let delegate
):
// We have a suspended yield at this point that hasn't been cancelled yet.
// We need to store the yield now.
@@ -1127,7 +1191,7 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal mutating func cancel(
internal mutating func cancel(
yieldID: YieldID
) -> CancelAction {
switch self._state {
@@ -1145,7 +1209,13 @@ extension NIOAsyncWriter {
return .none
case .streaming(let isWritable, let inDelegateOutcall, var cancelledYields, var suspendedYields, let delegate):
case .streaming(
let isWritable,
let inDelegateOutcall,
var cancelledYields,
var suspendedYields,
let delegate
):
if let index = suspendedYields.firstIndex(where: { $0.yieldID == yieldID }) {
self._state = .modifying
// We have a suspended yield for the id. We need to resume the continuation now.
@@ -1185,7 +1255,15 @@ extension NIOAsyncWriter {
return .none
}
case .writerFinished(let isWritable, let inDelegateOutcall, var suspendedYields, var cancelledYields, let bufferedYieldIDs, let delegate, let error):
case .writerFinished(
let isWritable,
let inDelegateOutcall,
var suspendedYields,
var cancelledYields,
let bufferedYieldIDs,
let delegate,
let error
):
guard bufferedYieldIDs.contains(yieldID) else {
return .none
}
@@ -1253,7 +1331,7 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal mutating func writerFinish(error: Error?) -> WriterFinishAction {
internal mutating func writerFinish(error: Error?) -> WriterFinishAction {
switch self._state {
case .initial(_, let delegate):
// Nothing was ever written so we can transition to finished
@@ -1261,7 +1339,13 @@ extension NIOAsyncWriter {
return .callDidTerminate(delegate)
case .streaming(let isWritable, let inDelegateOutcall, let cancelledYields, let suspendedYields, let delegate):
case .streaming(
let isWritable,
let inDelegateOutcall,
let cancelledYields,
let suspendedYields,
let delegate
):
// We are currently streaming and the writer got finished.
if suspendedYields.isEmpty {
if inDelegateOutcall {
@@ -1317,7 +1401,7 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal mutating func sinkFinish(error: Error?) -> SinkFinishAction {
internal mutating func sinkFinish(error: Error?) -> SinkFinishAction {
switch self._state {
case .initial(_, _):
// Nothing was ever written so we can transition to finished
@@ -1360,12 +1444,18 @@ extension NIOAsyncWriter {
}
@inlinable
/* fileprivate */ internal mutating func unbufferQueuedEvents() -> UnbufferQueuedEventsAction? {
internal mutating func unbufferQueuedEvents() -> UnbufferQueuedEventsAction? {
switch self._state {
case .initial:
preconditionFailure("Invalid state")
case .streaming(let isWritable, let inDelegateOutcall, let cancelledYields, let suspendedYields, let delegate):
case .streaming(
let isWritable,
let inDelegateOutcall,
let cancelledYields,
let suspendedYields,
let delegate
):
precondition(inDelegateOutcall, "We must be in a delegate outcall when we unbuffer events")
// We have to resume the other suspended yields now.
@@ -1391,7 +1481,15 @@ extension NIOAsyncWriter {
return .resumeContinuations(suspendedYields)
}
case .writerFinished(let isWritable, let inDelegateOutcall, let suspendedYields, let cancelledYields, let bufferedYieldIDs, let delegate, let error):
case .writerFinished(
let isWritable,
let inDelegateOutcall,
let suspendedYields,
let cancelledYields,
let bufferedYieldIDs,
let delegate,
let error
):
precondition(inDelegateOutcall, "We must be in a delegate outcall when we unbuffer events")
if suspendedYields.isEmpty {
// We were the last writer task and can now call didTerminate
@@ -1401,7 +1499,6 @@ extension NIOAsyncWriter {
// There are still other writer tasks that need to be resumed
self._state = .modifying
self._state = .writerFinished(
isWritable: isWritable,
inDelegateOutcall: inDelegateOutcall,
@@ -49,7 +49,7 @@ public struct NIOThrowingAsyncSequenceProducer<
public let sequence: NIOThrowingAsyncSequenceProducer
@usableFromInline
/* fileprivate */ internal init(
internal init(
source: Source,
sequence: NIOThrowingAsyncSequenceProducer
) {
@@ -62,7 +62,7 @@ public struct NIOThrowingAsyncSequenceProducer<
///
/// If we get move-only types we should be able to drop this class and use the `deinit` of the ``AsyncIterator`` struct itself.
@usableFromInline
/* fileprivate */ internal final class InternalClass: Sendable {
internal final class InternalClass: Sendable {
@usableFromInline
internal let _storage: Storage
@@ -78,10 +78,10 @@ public struct NIOThrowingAsyncSequenceProducer<
}
@usableFromInline
/* private */ internal let _internalClass: InternalClass
internal let _internalClass: InternalClass
@usableFromInline
/* private */ internal var _storage: Storage {
internal var _storage: Storage {
self._internalClass._storage
}
@@ -130,7 +130,11 @@ public struct NIOThrowingAsyncSequenceProducer<
/// - backPressureStrategy: The back-pressure strategy of the sequence.
/// - delegate: The delegate of the sequence
/// - Returns: A ``NIOThrowingAsyncSequenceProducer/Source`` and a ``NIOThrowingAsyncSequenceProducer``.
@available(*, deprecated, message: "Support for a generic Failure type is deprecated. Failure type must be `any Swift.Error`.")
@available(
*,
deprecated,
message: "Support for a generic Failure type is deprecated. Failure type must be `any Swift.Error`."
)
@inlinable
public static func makeSequence(
elementType: Element.Type = Element.self,
@@ -161,7 +165,12 @@ public struct NIOThrowingAsyncSequenceProducer<
/// - delegate: The delegate of the sequence
/// - Returns: A ``NIOThrowingAsyncSequenceProducer/Source`` and a ``NIOThrowingAsyncSequenceProducer``.
@inlinable
@available(*, deprecated, renamed: "makeSequence(elementType:failureType:backPressureStrategy:finishOnDeinit:delegate:)", message: "This method has been deprecated since it defaults to deinit based resource teardown")
@available(
*,
deprecated,
renamed: "makeSequence(elementType:failureType:backPressureStrategy:finishOnDeinit:delegate:)",
message: "This method has been deprecated since it defaults to deinit based resource teardown"
)
public static func makeSequence(
elementType: Element.Type = Element.self,
failureType: Failure.Type = Error.self,
@@ -195,7 +204,7 @@ public struct NIOThrowingAsyncSequenceProducer<
}
@inlinable
/* private */ internal init(
internal init(
backPressureStrategy: Strategy,
delegate: Delegate
) {
@@ -221,9 +230,9 @@ extension NIOThrowingAsyncSequenceProducer {
///
/// If we get move-only types we should be able to drop this class and use the `deinit` of the ``AsyncIterator`` struct itself.
@usableFromInline
/* private */ internal final class InternalClass: Sendable {
internal final class InternalClass: Sendable {
@usableFromInline
/* private */ internal let _storage: Storage
internal let _storage: Storage
fileprivate init(storage: Storage) {
self._storage = storage
@@ -236,13 +245,13 @@ extension NIOThrowingAsyncSequenceProducer {
}
@inlinable
/* fileprivate */ internal func next() async throws -> Element? {
internal func next() async throws -> Element? {
try await self._storage.next()
}
}
@usableFromInline
/* private */ internal let _internalClass: InternalClass
internal let _internalClass: InternalClass
fileprivate init(storage: Storage) {
self._internalClass = InternalClass(storage: storage)
@@ -268,7 +277,7 @@ extension NIOThrowingAsyncSequenceProducer {
///
/// - Important: This is safe to be unchecked ``Sendable`` since the `storage` is ``Sendable`` and `immutable`.
@usableFromInline
/* fileprivate */ internal final class InternalClass: Sendable {
internal final class InternalClass: Sendable {
@usableFromInline
internal let _storage: Storage
@@ -293,15 +302,15 @@ extension NIOThrowingAsyncSequenceProducer {
}
@usableFromInline
/* private */ internal let _internalClass: InternalClass
internal let _internalClass: InternalClass
@usableFromInline
/* private */ internal var _storage: Storage {
internal var _storage: Storage {
self._internalClass._storage
}
@usableFromInline
/* fileprivate */ internal init(storage: Storage, finishOnDeinit: Bool) {
internal init(storage: Storage, finishOnDeinit: Bool) {
self._internalClass = .init(storage: storage, finishOnDeinit: finishOnDeinit)
}
@@ -388,7 +397,7 @@ extension NIOThrowingAsyncSequenceProducer {
extension NIOThrowingAsyncSequenceProducer {
/// This is the underlying storage of the sequence. The goal of this is to synchronize the access to all state.
@usableFromInline
/* fileprivate */ internal struct Storage: Sendable {
internal struct Storage: Sendable {
@usableFromInline
struct State: Sendable {
@usableFromInline
@@ -426,7 +435,7 @@ extension NIOThrowingAsyncSequenceProducer {
}
@usableFromInline
/* fileprivate */ internal init(
internal init(
backPressureStrategy: Strategy,
delegate: Delegate
) {
@@ -438,7 +447,7 @@ extension NIOThrowingAsyncSequenceProducer {
}
@inlinable
/* fileprivate */ internal func sequenceDeinitialized() {
internal func sequenceDeinitialized() {
let delegate: Delegate? = self._state.withLockedValue {
let action = $0.stateMachine.sequenceDeinitialized()
@@ -457,14 +466,14 @@ extension NIOThrowingAsyncSequenceProducer {
}
@inlinable
/* fileprivate */ internal func iteratorInitialized() {
internal func iteratorInitialized() {
self._state.withLockedValue {
$0.stateMachine.iteratorInitialized()
}
}
@inlinable
/* fileprivate */ internal func iteratorDeinitialized() {
internal func iteratorDeinitialized() {
let delegate: Delegate? = self._state.withLockedValue {
let action = $0.stateMachine.iteratorDeinitialized()
@@ -484,7 +493,8 @@ extension NIOThrowingAsyncSequenceProducer {
}
@inlinable
/* fileprivate */ internal func yield<S: Sequence>(_ sequence: S) -> Source.YieldResult where S.Element == Element {
internal func yield<S: Sequence>(_ sequence: S) -> Source.YieldResult
where S.Element == Element {
// We must not resume the continuation while holding the lock
// because it can deadlock in combination with the underlying ulock
// in cases where we race with a cancellation handler
@@ -515,23 +525,24 @@ extension NIOThrowingAsyncSequenceProducer {
}
@inlinable
/* fileprivate */ internal func finish(_ failure: Failure?) {
internal func finish(_ failure: Failure?) {
// We must not resume the continuation while holding the lock
// because it can deadlock in combination with the underlying ulock
// in cases where we race with a cancellation handler
let (delegate, action): (Delegate?, NIOThrowingAsyncSequenceProducer.StateMachine.FinishAction) = self._state.withLockedValue {
let action = $0.stateMachine.finish(failure)
let (delegate, action): (Delegate?, NIOThrowingAsyncSequenceProducer.StateMachine.FinishAction) = self
._state.withLockedValue {
let action = $0.stateMachine.finish(failure)
switch action {
case .resumeContinuationWithFailureAndCallDidTerminate:
let delegate = $0.delegate
$0.delegate = nil
return (delegate, action)
switch action {
case .resumeContinuationWithFailureAndCallDidTerminate:
let delegate = $0.delegate
$0.delegate = nil
return (delegate, action)
case .none:
return (nil, action)
case .none:
return (nil, action)
}
}
}
switch action {
case .resumeContinuationWithFailureAndCallDidTerminate(let continuation, let failure):
@@ -550,7 +561,7 @@ extension NIOThrowingAsyncSequenceProducer {
}
@inlinable
/* fileprivate */ internal func next() async throws -> Element? {
internal func next() async throws -> Element? {
try await withTaskCancellationHandler { () async throws -> Element? in
let unsafe = self._state.unsafe
unsafe.lock()
@@ -614,7 +625,8 @@ extension NIOThrowingAsyncSequenceProducer {
case .suspendTask:
// It is safe to hold the lock across this method
// since the closure is guaranteed to be run straight away
return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Element?, any Error>) in
return try await withCheckedThrowingContinuation {
(continuation: CheckedContinuation<Element?, any Error>) in
let (action, callDidSuspend) = unsafe.withValueAssumingLockIsAcquired {
let action = $0.stateMachine.next(for: continuation)
let callDidSuspend = $0.didSuspend != nil
@@ -644,26 +656,27 @@ extension NIOThrowingAsyncSequenceProducer {
// We must not resume the continuation while holding the lock
// because it can deadlock in combination with the underlying ulock
// in cases where we race with a cancellation handler
let (delegate, action): (Delegate?, NIOThrowingAsyncSequenceProducer.StateMachine.CancelledAction) = self._state.withLockedValue {
let action = $0.stateMachine.cancelled()
let (delegate, action): (Delegate?, NIOThrowingAsyncSequenceProducer.StateMachine.CancelledAction) =
self._state.withLockedValue {
let action = $0.stateMachine.cancelled()
switch action {
case .callDidTerminate:
let delegate = $0.delegate
$0.delegate = nil
switch action {
case .callDidTerminate:
let delegate = $0.delegate
$0.delegate = nil
return (delegate, action)
return (delegate, action)
case .resumeContinuationWithCancellationErrorAndCallDidTerminate:
let delegate = $0.delegate
$0.delegate = nil
case .resumeContinuationWithCancellationErrorAndCallDidTerminate:
let delegate = $0.delegate
$0.delegate = nil
return (delegate, action)
return (delegate, action)
case .none:
return (nil, action)
case .none:
return (nil, action)
}
}
}
switch action {
case .callDidTerminate:
@@ -697,9 +710,9 @@ extension NIOThrowingAsyncSequenceProducer {
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
extension NIOThrowingAsyncSequenceProducer {
@usableFromInline
/* private */ internal struct StateMachine: Sendable {
internal struct StateMachine: Sendable {
@usableFromInline
/* private */ internal enum State: Sendable {
internal enum State: Sendable {
/// The initial state before either a call to `yield()` or a call to `next()` happened
case initial(
backPressureStrategy: Strategy,
@@ -736,7 +749,7 @@ extension NIOThrowingAsyncSequenceProducer {
/// The state machine's current state.
@usableFromInline
/* private */ internal var _state: State
internal var _state: State
@inlinable
var isFinished: Bool {
@@ -750,7 +763,6 @@ extension NIOThrowingAsyncSequenceProducer {
}
}
/// Initializes a new `StateMachine`.
///
/// We are passing and holding the back-pressure strategy here because
@@ -778,18 +790,18 @@ extension NIOThrowingAsyncSequenceProducer {
mutating func sequenceDeinitialized() -> SequenceDeinitializedAction {
switch self._state {
case .initial(_, iteratorInitialized: false),
.streaming(_, _, _, _, iteratorInitialized: false),
.sourceFinished(_, iteratorInitialized: false, _),
.cancelled(iteratorInitialized: false):
.streaming(_, _, _, _, iteratorInitialized: false),
.sourceFinished(_, iteratorInitialized: false, _),
.cancelled(iteratorInitialized: false):
// No iterator was created so we can transition to finished right away.
self._state = .finished(iteratorInitialized: false)
return .callDidTerminate
case .initial(_, iteratorInitialized: true),
.streaming(_, _, _, _, iteratorInitialized: true),
.sourceFinished(_, iteratorInitialized: true, _),
.cancelled(iteratorInitialized: true):
.streaming(_, _, _, _, iteratorInitialized: true),
.sourceFinished(_, iteratorInitialized: true, _),
.cancelled(iteratorInitialized: true):
// An iterator was created and we deinited the sequence.
// This is an expected pattern and we just continue on normal.
return .none
@@ -808,10 +820,10 @@ extension NIOThrowingAsyncSequenceProducer {
mutating func iteratorInitialized() {
switch self._state {
case .initial(_, iteratorInitialized: true),
.streaming(_, _, _, _, iteratorInitialized: true),
.sourceFinished(_, iteratorInitialized: true, _),
.cancelled(iteratorInitialized: true),
.finished(iteratorInitialized: true):
.streaming(_, _, _, _, iteratorInitialized: true),
.sourceFinished(_, iteratorInitialized: true, _),
.cancelled(iteratorInitialized: true),
.finished(iteratorInitialized: true):
// Our sequence is a unicast sequence and does not support multiple AsyncIterator's
fatalError("NIOThrowingAsyncSequenceProducer allows only a single AsyncIterator to be created")
@@ -868,16 +880,16 @@ extension NIOThrowingAsyncSequenceProducer {
mutating func iteratorDeinitialized() -> IteratorDeinitializedAction {
switch self._state {
case .initial(_, iteratorInitialized: false),
.streaming(_, _, _, _, iteratorInitialized: false),
.sourceFinished(_, iteratorInitialized: false, _),
.cancelled(iteratorInitialized: false):
.streaming(_, _, _, _, iteratorInitialized: false),
.sourceFinished(_, iteratorInitialized: false, _),
.cancelled(iteratorInitialized: false):
// An iterator needs to be initialized before it can be deinitialized.
preconditionFailure("Internal inconsistency")
case .initial(_, iteratorInitialized: true),
.streaming(_, _, _, _, iteratorInitialized: true),
.sourceFinished(_, iteratorInitialized: true, _),
.cancelled(iteratorInitialized: true):
.streaming(_, _, _, _, iteratorInitialized: true),
.sourceFinished(_, iteratorInitialized: true, _),
.cancelled(iteratorInitialized: true):
// An iterator was created and deinited. Since we only support
// a single iterator we can now transition to finish and inform the delegate.
self._state = .finished(iteratorInitialized: true)
@@ -917,7 +929,10 @@ extension NIOThrowingAsyncSequenceProducer {
case returnDropped
@usableFromInline
init(shouldProduceMore: Bool, continuationAndElement: (CheckedContinuation<Element?, Error>, Element)? = nil) {
init(
shouldProduceMore: Bool,
continuationAndElement: (CheckedContinuation<Element?, Error>, Element)? = nil
) {
switch (shouldProduceMore, continuationAndElement) {
case (true, .none):
self = .returnProduceMore
@@ -957,7 +972,13 @@ extension NIOThrowingAsyncSequenceProducer {
return .init(shouldProduceMore: shouldProduceMore)
case .streaming(var backPressureStrategy, var buffer, .some(let continuation), let hasOutstandingDemand, let iteratorInitialized):
case .streaming(
var backPressureStrategy,
var buffer,
.some(let continuation),
let hasOutstandingDemand,
let iteratorInitialized
):
// The buffer should always be empty if we hold a continuation
precondition(buffer.isEmpty, "Expected an empty buffer")
@@ -982,7 +1003,7 @@ extension NIOThrowingAsyncSequenceProducer {
self._state = .streaming(
backPressureStrategy: backPressureStrategy,
buffer: buffer,
continuation: nil, // Setting this to nil since we are resuming the continuation
continuation: nil, // Setting this to nil since we are resuming the continuation
hasOutstandingDemand: shouldProduceMore,
iteratorInitialized: iteratorInitialized
)
@@ -1167,7 +1188,13 @@ extension NIOThrowingAsyncSequenceProducer {
// We have multiple AsyncIterators iterating the sequence
preconditionFailure("This should never happen since we only allow a single Iterator to be created")
case .streaming(var backPressureStrategy, var buffer, .none, let hasOutstandingDemand, let iteratorInitialized):
case .streaming(
var backPressureStrategy,
var buffer,
.none,
let hasOutstandingDemand,
let iteratorInitialized
):
self._state = .modifying
if let element = buffer.popFirst() {
@@ -1252,7 +1279,13 @@ extension NIOThrowingAsyncSequenceProducer {
// We are transitioning away from the initial state in `next()`
preconditionFailure("Invalid state")
case .streaming(var backPressureStrategy, let buffer, .none, let hasOutstandingDemand, let iteratorInitialized):
case .streaming(
var backPressureStrategy,
let buffer,
.none,
let hasOutstandingDemand,
let iteratorInitialized
):
precondition(buffer.isEmpty, "Expected an empty buffer")
self._state = .modifying
+76 -58
View File
@@ -69,16 +69,21 @@ import Musl
import CNIOLinux
#if os(Android)
private let sysInet_ntop: @convention(c) (CInt, UnsafeRawPointer, UnsafeMutablePointer<CChar>, socklen_t) -> UnsafePointer<CChar>? = inet_ntop
private let sysInet_ntop:
@convention(c) (CInt, UnsafeRawPointer, UnsafeMutablePointer<CChar>, socklen_t) -> UnsafePointer<CChar>? = inet_ntop
private let sysInet_pton: @convention(c) (CInt, UnsafePointer<CChar>, UnsafeMutableRawPointer) -> CInt = inet_pton
#else
private let sysInet_ntop: @convention(c) (CInt, UnsafeRawPointer?, UnsafeMutablePointer<CChar>?, socklen_t) -> UnsafePointer<CChar>? = inet_ntop
private let sysInet_ntop:
@convention(c) (CInt, UnsafeRawPointer?, UnsafeMutablePointer<CChar>?, socklen_t) -> UnsafePointer<CChar>? =
inet_ntop
private let sysInet_pton: @convention(c) (CInt, UnsafePointer<CChar>?, UnsafeMutableRawPointer?) -> CInt = inet_pton
#endif
#elseif canImport(Darwin)
import Darwin
private let sysInet_ntop: @convention(c) (CInt, UnsafeRawPointer?, UnsafeMutablePointer<CChar>?, socklen_t) -> UnsafePointer<CChar>? = inet_ntop
private let sysInet_ntop:
@convention(c) (CInt, UnsafeRawPointer?, UnsafeMutablePointer<CChar>?, socklen_t) -> UnsafePointer<CChar>? =
inet_ntop
private let sysInet_pton: @convention(c) (CInt, UnsafePointer<CChar>?, UnsafeMutableRawPointer?) -> CInt = inet_pton
#else
#error("The BSD Socket module was unable to identify your C library.")
@@ -99,11 +104,11 @@ let SO_RCVTIMEO = CNIOLinux_SO_RCVTIMEO
#endif
public enum NIOBSDSocket {
#if os(Windows)
#if os(Windows)
public typealias Handle = SOCKET
#else
#else
public typealias Handle = CInt
#endif
#endif
}
extension NIOBSDSocket {
@@ -178,74 +183,73 @@ extension NIOBSDSocket.Option: Hashable {
extension NIOBSDSocket.AddressFamily {
/// Address for IP version 4.
public static let inet: NIOBSDSocket.AddressFamily =
NIOBSDSocket.AddressFamily(rawValue: AF_INET)
NIOBSDSocket.AddressFamily(rawValue: AF_INET)
/// Address for IP version 6.
public static let inet6: NIOBSDSocket.AddressFamily =
NIOBSDSocket.AddressFamily(rawValue: AF_INET6)
NIOBSDSocket.AddressFamily(rawValue: AF_INET6)
/// Unix local to host address.
public static let unix: NIOBSDSocket.AddressFamily =
NIOBSDSocket.AddressFamily(rawValue: AF_UNIX)
NIOBSDSocket.AddressFamily(rawValue: AF_UNIX)
}
// Protocol Family
extension NIOBSDSocket.ProtocolFamily {
/// IP network 4 protocol.
public static let inet: NIOBSDSocket.ProtocolFamily =
NIOBSDSocket.ProtocolFamily(rawValue: PF_INET)
NIOBSDSocket.ProtocolFamily(rawValue: PF_INET)
/// IP network 6 protocol.
public static let inet6: NIOBSDSocket.ProtocolFamily =
NIOBSDSocket.ProtocolFamily(rawValue: PF_INET6)
NIOBSDSocket.ProtocolFamily(rawValue: PF_INET6)
/// UNIX local to the host.
public static let unix: NIOBSDSocket.ProtocolFamily =
NIOBSDSocket.ProtocolFamily(rawValue: PF_UNIX)
NIOBSDSocket.ProtocolFamily(rawValue: PF_UNIX)
}
#if !os(Windows)
extension NIOBSDSocket.ProtocolFamily {
/// UNIX local to the host, alias for `PF_UNIX` (`.unix`)
public static let local: NIOBSDSocket.ProtocolFamily =
NIOBSDSocket.ProtocolFamily(rawValue: PF_LOCAL)
}
extension NIOBSDSocket.ProtocolFamily {
/// UNIX local to the host, alias for `PF_UNIX` (`.unix`)
public static let local: NIOBSDSocket.ProtocolFamily =
NIOBSDSocket.ProtocolFamily(rawValue: PF_LOCAL)
}
#endif
// Option Level
extension NIOBSDSocket.OptionLevel {
/// Socket options that apply only to IP sockets.
#if os(Linux) || os(Android)
public static let ip: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: CInt(IPPROTO_IP))
public static let ip: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: CInt(IPPROTO_IP))
#else
public static let ip: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_IP)
public static let ip: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_IP)
#endif
/// Socket options that apply only to IPv6 sockets.
#if os(Linux) || os(Android)
public static let ipv6: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: CInt(IPPROTO_IPV6))
public static let ipv6: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: CInt(IPPROTO_IPV6))
#elseif os(Windows)
public static let ipv6: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_IPV6.rawValue)
public static let ipv6: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_IPV6.rawValue)
#else
public static let ipv6: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_IPV6)
public static let ipv6: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_IPV6)
#endif
/// Socket options that apply only to TCP sockets.
#if os(Linux) || os(Android)
public static let tcp: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: CInt(IPPROTO_TCP))
public static let tcp: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: CInt(IPPROTO_TCP))
#elseif os(Windows)
public static let tcp: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_TCP.rawValue)
public static let tcp: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_TCP.rawValue)
#else
public static let tcp: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_TCP)
public static let tcp: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_TCP)
#endif
/// Socket options that apply to MPTCP sockets.
@@ -255,15 +259,15 @@ extension NIOBSDSocket.OptionLevel {
/// Socket options that apply to all sockets.
public static let socket: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: SOL_SOCKET)
NIOBSDSocket.OptionLevel(rawValue: SOL_SOCKET)
/// Socket options that apply only to UDP sockets.
#if os(Linux) || os(Android)
public static let udp: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: CInt(IPPROTO_UDP))
NIOBSDSocket.OptionLevel(rawValue: CInt(IPPROTO_UDP))
#else
public static let udp: NIOBSDSocket.OptionLevel =
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_UDP)
NIOBSDSocket.OptionLevel(rawValue: IPPROTO_UDP)
#endif
}
@@ -271,72 +275,72 @@ extension NIOBSDSocket.OptionLevel {
extension NIOBSDSocket.Option {
/// Add a multicast group membership.
public static let ip_add_membership: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IP_ADD_MEMBERSHIP)
NIOBSDSocket.Option(rawValue: IP_ADD_MEMBERSHIP)
/// Drop a multicast group membership.
public static let ip_drop_membership: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IP_DROP_MEMBERSHIP)
NIOBSDSocket.Option(rawValue: IP_DROP_MEMBERSHIP)
/// Set the interface for outgoing multicast packets.
public static let ip_multicast_if: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IP_MULTICAST_IF)
NIOBSDSocket.Option(rawValue: IP_MULTICAST_IF)
/// Control multicast loopback.
public static let ip_multicast_loop: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IP_MULTICAST_LOOP)
NIOBSDSocket.Option(rawValue: IP_MULTICAST_LOOP)
/// Control multicast time-to-live.
public static let ip_multicast_ttl: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IP_MULTICAST_TTL)
NIOBSDSocket.Option(rawValue: IP_MULTICAST_TTL)
/// The IPv4 layer generates an IP header when sending a packet
/// unless the ``ip_hdrincl`` socket option is enabled on the socket.
/// When it is enabled, the packet must contain an IP header. For
/// receiving, the IP header is always included in the packet.
public static let ip_hdrincl: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IP_HDRINCL)
NIOBSDSocket.Option(rawValue: IP_HDRINCL)
}
// IPv6 Options
extension NIOBSDSocket.Option {
/// Add an IPv6 group membership.
public static let ipv6_join_group: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IPV6_JOIN_GROUP)
NIOBSDSocket.Option(rawValue: IPV6_JOIN_GROUP)
/// Drop an IPv6 group membership.
public static let ipv6_leave_group: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IPV6_LEAVE_GROUP)
NIOBSDSocket.Option(rawValue: IPV6_LEAVE_GROUP)
/// Specify the maximum number of router hops for an IPv6 packet.
public static let ipv6_multicast_hops: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IPV6_MULTICAST_HOPS)
NIOBSDSocket.Option(rawValue: IPV6_MULTICAST_HOPS)
/// Set the interface for outgoing multicast packets.
public static let ipv6_multicast_if: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IPV6_MULTICAST_IF)
NIOBSDSocket.Option(rawValue: IPV6_MULTICAST_IF)
/// Control multicast loopback.
public static let ipv6_multicast_loop: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IPV6_MULTICAST_LOOP)
NIOBSDSocket.Option(rawValue: IPV6_MULTICAST_LOOP)
/// Indicates if a socket created for the `AF_INET6` address family is
/// restricted to IPv6 only.
public static let ipv6_v6only: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: IPV6_V6ONLY)
NIOBSDSocket.Option(rawValue: IPV6_V6ONLY)
}
// TCP Options
extension NIOBSDSocket.Option {
/// Disables the Nagle algorithm for send coalescing.
public static let tcp_nodelay: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: TCP_NODELAY)
NIOBSDSocket.Option(rawValue: TCP_NODELAY)
}
#if os(Linux) || os(FreeBSD) || os(Android)
extension NIOBSDSocket.Option {
/// Get information about the TCP connection.
public static let tcp_info: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: TCP_INFO)
NIOBSDSocket.Option(rawValue: TCP_INFO)
}
#endif
@@ -344,7 +348,7 @@ extension NIOBSDSocket.Option {
extension NIOBSDSocket.Option {
/// Get information about the TCP connection.
public static let tcp_connection_info: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: TCP_CONNECTION_INFO)
NIOBSDSocket.Option(rawValue: TCP_CONNECTION_INFO)
}
#endif
@@ -398,14 +402,18 @@ extension NIOBSDSocket.Option {
extension NIOBSDSocket.Option {
/// Indicate when to generate timestamps.
public static let so_timestamp: NIOBSDSocket.Option =
NIOBSDSocket.Option(rawValue: SO_TIMESTAMP)
NIOBSDSocket.Option(rawValue: SO_TIMESTAMP)
}
#endif
extension NIOBSDSocket {
// Sadly this was defined on BSDSocket, and we need it for SocketAddress.
@inline(never)
internal static func inet_pton(addressFamily: NIOBSDSocket.AddressFamily, addressDescription: UnsafePointer<CChar>, address: UnsafeMutableRawPointer) throws {
internal static func inet_pton(
addressFamily: NIOBSDSocket.AddressFamily,
addressDescription: UnsafePointer<CChar>,
address: UnsafeMutableRawPointer
) throws {
#if os(Windows)
// TODO(compnerd) use `InetPtonW` to ensure that we handle unicode properly
switch WinSDK.inet_pton(addressFamily.rawValue, addressDescription, address) {
@@ -424,12 +432,22 @@ extension NIOBSDSocket {
@discardableResult
@inline(never)
internal static func inet_ntop(addressFamily: NIOBSDSocket.AddressFamily, addressBytes: UnsafeRawPointer, addressDescription: UnsafeMutablePointer<CChar>, addressDescriptionLength: socklen_t) throws -> UnsafePointer<CChar> {
internal static func inet_ntop(
addressFamily: NIOBSDSocket.AddressFamily,
addressBytes: UnsafeRawPointer,
addressDescription: UnsafeMutablePointer<CChar>,
addressDescriptionLength: socklen_t
) throws -> UnsafePointer<CChar> {
#if os(Windows)
// TODO(compnerd) use `InetNtopW` to ensure that we handle unicode properly
guard let result = WinSDK.inet_ntop(addressFamily.rawValue, addressBytes,
addressDescription,
Int(addressDescriptionLength)) else {
guard
let result = WinSDK.inet_ntop(
addressFamily.rawValue,
addressBytes,
addressDescription,
Int(addressDescriptionLength)
)
else {
throw IOError(windows: GetLastError(), reason: "inet_ntop")
}
return result
+69 -54
View File
@@ -36,7 +36,7 @@ extension ByteBuffer {
// this is not technically correct because we shouldn't just bind
// the memory to `UInt8` but it's not a real issue either and we
// need to work around https://bugs.swift.org/browse/SR-9604
Array<UInt8>(UnsafeRawBufferPointer(fastRebase: ptr[range]).bindMemory(to: UInt8.self))
[UInt8](UnsafeRawBufferPointer(fastRebase: ptr[range]).bindMemory(to: UInt8.self))
}
}
@@ -79,8 +79,13 @@ extension ByteBuffer {
@inlinable
public mutating func setStaticString(_ string: StaticString, at index: Int) -> Int {
// please do not replace the code below with code that uses `string.withUTF8Buffer { ... }` (see SR-7541)
return self.setBytes(UnsafeRawBufferPointer(start: string.utf8Start,
count: string.utf8CodeUnitCount), at: index)
self.setBytes(
UnsafeRawBufferPointer(
start: string.utf8Start,
count: string.utf8CodeUnitCount
),
at: index
)
}
// MARK: String APIs
@@ -96,7 +101,7 @@ extension ByteBuffer {
self._moveWriterIndex(forwardBy: written)
return written
}
/// Write `string` into this `ByteBuffer` null terminated using UTF-8 encoding, moving the writer index forward appropriately.
///
/// - parameters:
@@ -144,7 +149,7 @@ extension ByteBuffer {
return self._setStringSlowpath(string, at: index)
}
}
/// Write `string` null terminated into this `ByteBuffer` at `index` using UTF-8 encoding. Does not move the writer index.
///
/// - parameters:
@@ -176,7 +181,7 @@ extension ByteBuffer {
return String(decoding: UnsafeRawBufferPointer(fastRebase: pointer[range]), as: Unicode.UTF8.self)
}
}
/// Get the string at `index` from this `ByteBuffer` decoding using the UTF-8 encoding. Does not move the reader index.
/// The selected bytes must be readable or else `nil` will be returned.
///
@@ -216,7 +221,7 @@ extension ByteBuffer {
self._moveReaderIndex(forwardBy: length)
return result
}
/// Read a null terminated string off this `ByteBuffer`, decoding it as `String` using the UTF-8 encoding. Move the reader index
/// forward by the string's length and its null terminator.
///
@@ -228,7 +233,7 @@ extension ByteBuffer {
return nil
}
let result = self.readString(length: stringLength)
self.moveReaderIndex(forwardBy: 1) // move forward by null terminator
self.moveReaderIndex(forwardBy: 1) // move forward by null terminator
return result
}
@@ -245,7 +250,7 @@ extension ByteBuffer {
self._moveWriterIndex(forwardBy: written)
return written
}
/// Write `substring` into this `ByteBuffer` at `index` using UTF-8 encoding. Does not move the writer index.
///
/// - parameters:
@@ -267,7 +272,7 @@ extension ByteBuffer {
return self.setString(String(substring), at: index)
}
}
// MARK: DispatchData APIs
/// Write `dispatchData` into this `ByteBuffer`, moving the writer index forward appropriately.
///
@@ -295,7 +300,7 @@ extension ByteBuffer {
self.reserveCapacity(index + allBytesCount)
self.withVeryUnsafeMutableBytes { destCompleteStorage in
assert(destCompleteStorage.count >= index + allBytesCount)
let dest = destCompleteStorage[index ..< index + allBytesCount]
let dest = destCompleteStorage[index..<index + allBytesCount]
dispatchData.copyBytes(to: .init(fastRebase: dest), count: dest.count)
}
return allBytesCount
@@ -315,7 +320,7 @@ extension ByteBuffer {
return nil
}
return self.withUnsafeReadableBytes { pointer in
return DispatchData(bytes: UnsafeRawBufferPointer(fastRebase: pointer[range]))
DispatchData(bytes: UnsafeRawBufferPointer(fastRebase: pointer[range]))
}
}
@@ -333,7 +338,6 @@ extension ByteBuffer {
return result
}
// MARK: Other APIs
/// Yields an immutable buffer pointer containing this `ByteBuffer`'s readable bytes. Will move the reader index
@@ -352,21 +356,6 @@ extension ByteBuffer {
return bytesRead
}
/// Yields an immutable buffer pointer containing this `ByteBuffer`'s readable bytes. Will move the reader index
/// by the number of bytes `body` returns in the first tuple component.
///
/// - warning: Do not escape the pointer from the closure for later use.
///
/// - parameters:
/// - body: The closure that will accept the yielded bytes and returns the number of bytes it processed along with some other value.
/// - returns: The value `body` returned in the second tuple component.
@inlinable
public mutating func readWithUnsafeReadableBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> (Int, T)) rethrows -> T {
let (bytesRead, ret) = try self.withUnsafeReadableBytes({ try body($0) })
self._moveReaderIndex(forwardBy: bytesRead)
return ret
}
/// Yields a mutable buffer pointer containing this `ByteBuffer`'s readable bytes. You may modify the yielded bytes.
/// Will move the reader index by the number of bytes returned by `body` but leave writer index as it was.
///
@@ -377,27 +366,14 @@ extension ByteBuffer {
/// - returns: The number of bytes read.
@discardableResult
@inlinable
public mutating func readWithUnsafeMutableReadableBytes(_ body: (UnsafeMutableRawBufferPointer) throws -> Int) rethrows -> Int {
public mutating func readWithUnsafeMutableReadableBytes(
_ body: (UnsafeMutableRawBufferPointer) throws -> Int
) rethrows -> Int {
let bytesRead = try self.withUnsafeMutableReadableBytes({ try body($0) })
self._moveReaderIndex(forwardBy: bytesRead)
return bytesRead
}
/// Yields a mutable buffer pointer containing this `ByteBuffer`'s readable bytes. You may modify the yielded bytes.
/// Will move the reader index by the number of bytes `body` returns in the first tuple component but leave writer index as it was.
///
/// - warning: Do not escape the pointer from the closure for later use.
///
/// - parameters:
/// - body: The closure that will accept the yielded bytes and returns the number of bytes it processed along with some other value.
/// - returns: The value `body` returned in the second tuple component.
@inlinable
public mutating func readWithUnsafeMutableReadableBytes<T>(_ body: (UnsafeMutableRawBufferPointer) throws -> (Int, T)) rethrows -> T {
let (bytesRead, ret) = try self.withUnsafeMutableReadableBytes({ try body($0) })
self._moveReaderIndex(forwardBy: bytesRead)
return ret
}
/// Copy `buffer`'s readable bytes into this `ByteBuffer` starting at `index`. Does not move any of the reader or writer indices.
///
/// - parameters:
@@ -407,7 +383,7 @@ extension ByteBuffer {
@discardableResult
@available(*, deprecated, renamed: "setBuffer(_:at:)")
public mutating func set(buffer: ByteBuffer, at index: Int) -> Int {
return self.setBuffer(buffer, at: index)
self.setBuffer(buffer, at: index)
}
/// Copy `buffer`'s readable bytes into this `ByteBuffer` starting at `index`. Does not move any of the reader or writer indices.
@@ -419,7 +395,7 @@ extension ByteBuffer {
@discardableResult
@inlinable
public mutating func setBuffer(_ buffer: ByteBuffer, at index: Int) -> Int {
return buffer.withUnsafeReadableBytes{ p in
buffer.withUnsafeReadableBytes { p in
self.setBytes(p, at: index)
}
}
@@ -464,7 +440,7 @@ extension ByteBuffer {
self._moveWriterIndex(forwardBy: written)
return written
}
/// Writes `byte` `count` times. Moves the writer index forward by the number of bytes written.
///
/// - parameter byte: The `UInt8` byte to repeat.
@@ -477,7 +453,7 @@ extension ByteBuffer {
self._moveWriterIndex(forwardBy: written)
return written
}
/// Sets the given `byte` `count` times at the given `index`. Will reserve more memory if necessary. Does not move the writer index.
///
/// - parameter byte: The `UInt8` byte to repeat.
@@ -489,7 +465,7 @@ extension ByteBuffer {
precondition(count >= 0, "Can't write fewer than 0 bytes")
self.reserveCapacity(index + count)
self.withVeryUnsafeMutableBytes { pointer in
let dest = UnsafeMutableRawBufferPointer(fastRebase: pointer[index ..< index+count])
let dest = UnsafeMutableRawBufferPointer(fastRebase: pointer[index..<index + count])
_ = dest.initializeMemory(as: UInt8.self, repeating: byte)
}
return count
@@ -504,7 +480,8 @@ extension ByteBuffer {
/// - returns: A `ByteBuffer` sharing storage containing the readable bytes only.
@inlinable
public func slice() -> ByteBuffer {
return self.getSlice(at: self.readerIndex, length: self.readableBytes)! // must work, bytes definitely in the buffer
// must work, bytes definitely in the buffer// must work, bytes definitely in the buffer
self.getSlice(at: self.readerIndex, length: self.readableBytes)!
}
/// Slice `length` bytes off this `ByteBuffer` and move the reader index forward by `length`.
@@ -536,6 +513,43 @@ extension ByteBuffer {
}
}
// swift-format-ignore: AmbiguousTrailingClosureOverload
extension ByteBuffer {
/// Yields a mutable buffer pointer containing this `ByteBuffer`'s readable bytes. You may modify the yielded bytes.
/// Will move the reader index by the number of bytes `body` returns in the first tuple component but leave writer index as it was.
///
/// - warning: Do not escape the pointer from the closure for later use.
///
/// - parameters:
/// - body: The closure that will accept the yielded bytes and returns the number of bytes it processed along with some other value.
/// - returns: The value `body` returned in the second tuple component.
@inlinable
public mutating func readWithUnsafeMutableReadableBytes<T>(
_ body: (UnsafeMutableRawBufferPointer) throws -> (Int, T)
) rethrows -> T {
let (bytesRead, ret) = try self.withUnsafeMutableReadableBytes({ try body($0) })
self._moveReaderIndex(forwardBy: bytesRead)
return ret
}
/// Yields an immutable buffer pointer containing this `ByteBuffer`'s readable bytes. Will move the reader index
/// by the number of bytes `body` returns in the first tuple component.
///
/// - warning: Do not escape the pointer from the closure for later use.
///
/// - parameters:
/// - body: The closure that will accept the yielded bytes and returns the number of bytes it processed along with some other value.
/// - returns: The value `body` returned in the second tuple component.
@inlinable
public mutating func readWithUnsafeReadableBytes<T>(
_ body: (UnsafeRawBufferPointer) throws -> (Int, T)
) rethrows -> T {
let (bytesRead, ret) = try self.withUnsafeReadableBytes({ try body($0) })
self._moveReaderIndex(forwardBy: bytesRead)
return ret
}
}
extension ByteBuffer {
/// Return an empty `ByteBuffer` allocated with `ByteBufferAllocator()`.
///
@@ -749,9 +763,11 @@ extension ByteBufferAllocator {
///
/// - returns: The `ByteBuffer` containing the written bytes.
@inlinable
public func buffer<I: FixedWidthInteger>(integer: I,
endianness: Endianness = .big,
as: I.Type = I.self) -> ByteBuffer {
public func buffer<I: FixedWidthInteger>(
integer: I,
endianness: Endianness = .big,
as: I.Type = I.self
) -> ByteBuffer {
var buffer = self.buffer(capacity: MemoryLayout<I>.size)
buffer.writeInteger(integer, endianness: endianness, as: `as`)
return buffer
@@ -799,7 +815,6 @@ extension ByteBufferAllocator {
}
}
extension Optional where Wrapped == ByteBuffer {
/// If `nil`, replace `self` with `.some(buffer)`. If non-`nil`, write `buffer`'s readable bytes into the
/// `ByteBuffer` starting at `writerIndex`.
+5 -5
View File
@@ -15,7 +15,7 @@
import Dispatch
extension Array where Element == UInt8 {
/// Creates a `[UInt8]` from the given buffer. The entire readable portion of the buffer will be read.
/// - parameter buffer: The buffer to read.
@inlinable
@@ -23,11 +23,11 @@ extension Array where Element == UInt8 {
var buffer = buffer
self = buffer.readBytes(length: buffer.readableBytes)!
}
}
extension String {
/// Creates a `String` from a given `ByteBuffer`. The entire readable portion of the buffer will be read.
/// - parameter buffer: The buffer to read.
@inlinable
@@ -49,7 +49,7 @@ extension String {
}
extension DispatchData {
/// Creates a `DispatchData` from a given `ByteBuffer`. The entire readable portion of the buffer will be read.
/// - parameter buffer: The buffer to read.
@inlinable
@@ -57,5 +57,5 @@ extension DispatchData {
var buffer = buffer
self = buffer.readDispatchData(length: buffer.readableBytes)!
}
}
+147 -78
View File
@@ -25,7 +25,8 @@ import Musl
#endif
@usableFromInline let sysMalloc: @convention(c) (size_t) -> UnsafeMutableRawPointer? = malloc
@usableFromInline let sysRealloc: @convention(c) (UnsafeMutableRawPointer?, size_t) -> UnsafeMutableRawPointer? = realloc
@usableFromInline let sysRealloc: @convention(c) (UnsafeMutableRawPointer?, size_t) -> UnsafeMutableRawPointer? =
realloc
/// Xcode 13 GM shipped with a bug in the SDK that caused `free`'s first argument to be annotated as
/// non-nullable. To that end, we define a thunk through to `free` that matches that constraint, as we
@@ -42,19 +43,19 @@ struct _ByteBufferSlice: Sendable {
@usableFromInline private(set) var upperBound: ByteBuffer._Index
@usableFromInline private(set) var _begin: _UInt24
@inlinable var lowerBound: ByteBuffer._Index {
return UInt32(self._begin)
UInt32(self._begin)
}
@inlinable var count: Int {
// Safe: the only constructors that set this enforce that upperBound > lowerBound, so
// this cannot underflow.
return Int(self.upperBound &- self.lowerBound)
Int(self.upperBound &- self.lowerBound)
}
@inlinable init() {
self._begin = .init(0)
self.upperBound = .init(0)
}
@inlinable static var maxSupportedLowerBound: ByteBuffer._Index {
return ByteBuffer._Index(_UInt24.max)
ByteBuffer._Index(_UInt24.max)
}
}
@@ -68,7 +69,7 @@ extension _ByteBufferSlice {
extension _ByteBufferSlice: CustomStringConvertible {
@usableFromInline
var description: String {
return "_ByteBufferSlice { \(self.lowerBound)..<\(self.upperBound) }"
"_ByteBufferSlice { \(self.lowerBound)..<\(self.upperBound) }"
}
}
@@ -82,17 +83,21 @@ public struct ByteBufferAllocator: Sendable {
/// therefore it's recommended to reuse `ByteBufferAllocators` where possible instead of creating fresh ones in
/// many places.
@inlinable public init() {
self.init(hookedMalloc: { sysMalloc($0) },
hookedRealloc: { sysRealloc($0, $1) },
hookedFree: { sysFree($0) },
hookedMemcpy: { $0.copyMemory(from: $1, byteCount: $2) })
self.init(
hookedMalloc: { sysMalloc($0) },
hookedRealloc: { sysRealloc($0, $1) },
hookedFree: { sysFree($0) },
hookedMemcpy: { $0.copyMemory(from: $1, byteCount: $2) }
)
}
@inlinable
internal init(hookedMalloc: @escaping @convention(c) (size_t) -> UnsafeMutableRawPointer?,
hookedRealloc: @escaping @convention(c) (UnsafeMutableRawPointer?, size_t) -> UnsafeMutableRawPointer?,
hookedFree: @escaping @convention(c) (UnsafeMutableRawPointer) -> Void,
hookedMemcpy: @escaping @convention(c) (UnsafeMutableRawPointer, UnsafeRawPointer, size_t) -> Void) {
internal init(
hookedMalloc: @escaping @convention(c) (size_t) -> UnsafeMutableRawPointer?,
hookedRealloc: @escaping @convention(c) (UnsafeMutableRawPointer?, size_t) -> UnsafeMutableRawPointer?,
hookedFree: @escaping @convention(c) (UnsafeMutableRawPointer) -> Void,
hookedMemcpy: @escaping @convention(c) (UnsafeMutableRawPointer, UnsafeRawPointer, size_t) -> Void
) {
self.malloc = hookedMalloc
self.realloc = hookedRealloc
self.free = hookedFree
@@ -118,20 +123,24 @@ public struct ByteBufferAllocator: Sendable {
}
@usableFromInline
internal static let zeroCapacityWithDefaultAllocator = ByteBuffer(allocator: ByteBufferAllocator(), startingCapacity: 0)
internal static let zeroCapacityWithDefaultAllocator = ByteBuffer(
allocator: ByteBufferAllocator(),
startingCapacity: 0
)
@usableFromInline internal let malloc: @convention(c) (size_t) -> UnsafeMutableRawPointer?
@usableFromInline internal let realloc: @convention(c) (UnsafeMutableRawPointer?, size_t) -> UnsafeMutableRawPointer?
@usableFromInline internal let realloc:
@convention(c) (UnsafeMutableRawPointer?, size_t) -> UnsafeMutableRawPointer?
@usableFromInline internal let free: @convention(c) (UnsafeMutableRawPointer) -> Void
@usableFromInline internal let memcpy: @convention(c) (UnsafeMutableRawPointer, UnsafeRawPointer, size_t) -> Void
}
@inlinable func _toCapacity(_ value: Int) -> ByteBuffer._Capacity {
return ByteBuffer._Capacity(truncatingIfNeeded: value)
ByteBuffer._Capacity(truncatingIfNeeded: value)
}
@inlinable func _toIndex(_ value: Int) -> ByteBuffer._Index {
return ByteBuffer._Index(truncatingIfNeeded: value)
ByteBuffer._Index(truncatingIfNeeded: value)
}
/// `ByteBuffer` stores contiguously allocated raw bytes. It is a random and sequential accessible sequence of zero or
@@ -283,28 +292,30 @@ public struct ByteBuffer {
@inlinable
var fullSlice: _ByteBufferSlice {
return _ByteBufferSlice(0..<self.capacity)
_ByteBufferSlice(0..<self.capacity)
}
@inlinable
static func _allocateAndPrepareRawMemory(bytes: _Capacity, allocator: Allocator) -> UnsafeMutableRawPointer {
let ptr = allocator.malloc(size_t(bytes))!
/* bind the memory so we can assume it elsewhere to be bound to UInt8 */
// bind the memory so we can assume it elsewhere to be bound to UInt8
ptr.bindMemory(to: UInt8.self, capacity: Int(bytes))
return ptr
}
@inlinable
func allocateStorage() -> _Storage {
return self.allocateStorage(capacity: self.capacity)
self.allocateStorage(capacity: self.capacity)
}
@inlinable
func allocateStorage(capacity: _Capacity) -> _Storage {
let newCapacity = capacity == 0 ? 0 : capacity.nextPowerOf2ClampedToMax()
return _Storage(bytesNoCopy: _Storage._allocateAndPrepareRawMemory(bytes: newCapacity, allocator: self.allocator),
capacity: newCapacity,
allocator: self.allocator)
return _Storage(
bytesNoCopy: _Storage._allocateAndPrepareRawMemory(bytes: newCapacity, allocator: self.allocator),
capacity: newCapacity,
allocator: self.allocator
)
}
@inlinable
@@ -319,7 +330,7 @@ public struct ByteBuffer {
func reallocStorage(capacity minimumNeededCapacity: _Capacity) {
let newCapacity = minimumNeededCapacity.nextPowerOf2ClampedToMax()
let ptr = self.allocator.realloc(self.bytes, size_t(newCapacity))!
/* bind the memory so we can assume it elsewhere to be bound to UInt8 */
// bind the memory so we can assume it elsewhere to be bound to UInt8
ptr.bindMemory(to: UInt8.self, capacity: Int(newCapacity))
self.bytes = ptr
self.capacity = newCapacity
@@ -333,15 +344,17 @@ public struct ByteBuffer {
static func reallocated(minimumCapacity: _Capacity, allocator: Allocator) -> _Storage {
let newCapacity = minimumCapacity == 0 ? 0 : minimumCapacity.nextPowerOf2ClampedToMax()
// TODO: Use realloc if possible
return _Storage(bytesNoCopy: _Storage._allocateAndPrepareRawMemory(bytes: newCapacity, allocator: allocator),
capacity: newCapacity,
allocator: allocator)
return _Storage(
bytesNoCopy: _Storage._allocateAndPrepareRawMemory(bytes: newCapacity, allocator: allocator),
capacity: newCapacity,
allocator: allocator
)
}
func dumpBytes(slice: Slice, offset: Int, length: Int) -> String {
var desc = "["
let bytes = UnsafeRawBufferPointer(start: self.bytes, count: Int(self.capacity))
for byte in bytes[Int(slice.lowerBound) + offset ..< Int(slice.lowerBound) + offset + length] {
for byte in bytes[Int(slice.lowerBound) + offset..<Int(slice.lowerBound) + offset + length] {
let hexByte = String(byte, radix: 16)
desc += " \(hexByte.count == 1 ? "0" : "")\(hexByte)"
}
@@ -393,7 +406,7 @@ public struct ByteBuffer {
let storageUpperBound = min(self._slice.upperBound, storageRebaseAmount + capacity)
// Step 4: Allocate the new buffer and copy the slice of bytes we want to keep.
let newSlice = storageRebaseAmount ..< storageUpperBound
let newSlice = storageRebaseAmount..<storageUpperBound
self._storage = self._storage.reallocSlice(newSlice, capacity: capacity)
// Step 5: Fixup the indices. These should never trap, but we're going to leave them checked because this method is fiddly.
@@ -425,18 +438,23 @@ public struct ByteBuffer {
if self._slice.lowerBound == 0 {
self._storage.reallocStorage(capacity: newStorageMinCapacity)
} else {
self._storage = self._storage.reallocSlice(self._slice.lowerBound ..< self._slice.upperBound,
capacity: newStorageMinCapacity)
self._storage = self._storage.reallocSlice(
self._slice.lowerBound..<self._slice.upperBound,
capacity: newStorageMinCapacity
)
}
self._slice = self._storage.fullSlice
} else {
// yes, let's just extend the slice until the end of the buffer
self._slice = _ByteBufferSlice(_slice.lowerBound ..< self._storage.capacity)
self._slice = _ByteBufferSlice(_slice.lowerBound..<self._storage.capacity)
}
}
assert(self._slice.lowerBound + index + capacity <= self._slice.upperBound)
assert(self._slice.lowerBound >= 0, "illegal slice: negative lower bound: \(self._slice.lowerBound)")
assert(self._slice.upperBound <= self._storage.capacity, "illegal slice: upper bound (\(self._slice.upperBound)) exceeds capacity: \(self._storage.capacity)")
assert(
self._slice.upperBound <= self._storage.capacity,
"illegal slice: upper bound (\(self._slice.upperBound)) exceeds capacity: \(self._storage.capacity)"
)
}
// MARK: Internal API
@@ -487,10 +505,13 @@ public struct ByteBuffer {
@inline(never)
@inlinable
@_specialize(where Bytes == CircularBuffer<UInt8>)
mutating func _setSlowPath<Bytes: Sequence>(bytes: Bytes, at index: _Index) -> _Capacity where Bytes.Element == UInt8 {
mutating func _setSlowPath<Bytes: Sequence>(bytes: Bytes, at index: _Index) -> _Capacity
where Bytes.Element == UInt8 {
func ensureCapacityAndReturnStorageBase(capacity: Int) -> UnsafeMutablePointer<UInt8> {
self._ensureAvailableCapacity(_Capacity(capacity), at: index)
let newBytesPtr = UnsafeMutableRawBufferPointer(fastRebase: self._slicedStorageBuffer[Int(index) ..< Int(index) + Int(capacity)])
let newBytesPtr = UnsafeMutableRawBufferPointer(
fastRebase: self._slicedStorageBuffer[Int(index)..<Int(index) + Int(capacity)]
)
return newBytesPtr.bindMemory(to: UInt8.self).baseAddress!
}
let underestimatedByteCount = bytes.underestimatedCount
@@ -501,7 +522,9 @@ public struct ByteBuffer {
}
var base = ensureCapacityAndReturnStorageBase(capacity: underestimatedByteCount)
var (iterator, idx) = UnsafeMutableBufferPointer(start: base, count: underestimatedByteCount).initialize(from: bytes)
var (iterator, idx) = UnsafeMutableBufferPointer(start: base, count: underestimatedByteCount).initialize(
from: bytes
)
assert(idx == underestimatedByteCount)
while let b = iterator.next() {
base = ensureCapacityAndReturnStorageBase(capacity: idx + 1)
@@ -512,7 +535,8 @@ public struct ByteBuffer {
}
@inlinable
mutating func _setBytes<Bytes: Sequence>(_ bytes: Bytes, at index: _Index) -> _Capacity where Bytes.Element == UInt8 {
mutating func _setBytes<Bytes: Sequence>(_ bytes: Bytes, at index: _Index) -> _Capacity
where Bytes.Element == UInt8 {
if let written = bytes.withContiguousStorageIfAvailable({ bytes in
self._setBytes(UnsafeRawBufferPointer(bytes), at: index)
}) {
@@ -537,20 +561,20 @@ public struct ByteBuffer {
/// trigger a copy of the bytes.
@inlinable public var writableBytes: Int {
// this cannot over/overflow because both values are positive and writerIndex<=slice.count, checked on ingestion
return Int(_toCapacity(self._slice.count) &- self._writerIndex)
Int(_toCapacity(self._slice.count) &- self._writerIndex)
}
/// The number of bytes readable (`readableBytes` = `writerIndex` - `readerIndex`).
@inlinable public var readableBytes: Int {
// this cannot under/overflow because both are positive and writer >= reader (checked on ingestion of bytes).
return Int(self._writerIndex &- self._readerIndex)
Int(self._writerIndex &- self._readerIndex)
}
/// The current capacity of the storage of this `ByteBuffer`, this is not constant and does _not_ signify the number
/// of bytes that have been written to this `ByteBuffer`.
@inlinable
public var capacity: Int {
return self._slice.count
self._slice.count
}
/// The current capacity of the underlying storage of this `ByteBuffer`.
@@ -558,7 +582,7 @@ public struct ByteBuffer {
/// buffer until new data is written.
@inlinable
public var storageCapacity: Int {
return self._storage.fullSlice.count
self._storage.fullSlice.count
}
/// Reserves enough space to store the specified number of bytes.
@@ -597,7 +621,7 @@ public struct ByteBuffer {
/// - Parameter minimumWritableBytes: The minimum number of writable bytes this buffer must have.
@inlinable
public mutating func reserveCapacity(minimumWritableBytes: Int) {
return self.reserveCapacity(self.writerIndex + minimumWritableBytes)
self.reserveCapacity(self.writerIndex + minimumWritableBytes)
}
@inlinable
@@ -610,8 +634,10 @@ public struct ByteBuffer {
@inlinable
var _slicedStorageBuffer: UnsafeMutableRawBufferPointer {
return UnsafeMutableRawBufferPointer(start: self._storage.bytes.advanced(by: Int(self._slice.lowerBound)),
count: self._slice.count)
UnsafeMutableRawBufferPointer(
start: self._storage.bytes.advanced(by: Int(self._slice.lowerBound)),
count: self._slice.count
)
}
/// Yields a mutable buffer pointer containing this `ByteBuffer`'s readable bytes. You may modify those bytes.
@@ -622,7 +648,9 @@ public struct ByteBuffer {
/// - body: The closure that will accept the yielded bytes.
/// - returns: The value returned by `body`.
@inlinable
public mutating func withUnsafeMutableReadableBytes<T>(_ body: (UnsafeMutableRawBufferPointer) throws -> T) rethrows -> T {
public mutating func withUnsafeMutableReadableBytes<T>(
_ body: (UnsafeMutableRawBufferPointer) throws -> T
) rethrows -> T {
self._copyStorageAndRebaseIfNeeded()
// this is safe because we always know that readerIndex >= writerIndex
let range = Range<Int>(uncheckedBounds: (lower: self.readerIndex, upper: self.writerIndex))
@@ -640,7 +668,9 @@ public struct ByteBuffer {
/// - body: The closure that will accept the yielded bytes and return the number of bytes written.
/// - returns: The number of bytes written.
@inlinable
public mutating func withUnsafeMutableWritableBytes<T>(_ body: (UnsafeMutableRawBufferPointer) throws -> T) rethrows -> T {
public mutating func withUnsafeMutableWritableBytes<T>(
_ body: (UnsafeMutableRawBufferPointer) throws -> T
) rethrows -> T {
self._copyStorageAndRebaseIfNeeded()
return try body(.init(fastRebase: self._slicedStorageBuffer.dropFirst(self.writerIndex)))
}
@@ -655,7 +685,10 @@ public struct ByteBuffer {
/// - returns: The number of bytes written.
@discardableResult
@inlinable
public mutating func writeWithUnsafeMutableBytes(minimumWritableBytes: Int, _ body: (UnsafeMutableRawBufferPointer) throws -> Int) rethrows -> Int {
public mutating func writeWithUnsafeMutableBytes(
minimumWritableBytes: Int,
_ body: (UnsafeMutableRawBufferPointer) throws -> Int
) rethrows -> Int {
if minimumWritableBytes > 0 {
self.reserveCapacity(minimumWritableBytes: minimumWritableBytes)
}
@@ -664,11 +697,18 @@ public struct ByteBuffer {
return bytesWritten
}
@available(*, deprecated, message: "please use writeWithUnsafeMutableBytes(minimumWritableBytes:_:) instead to ensure sufficient write capacity.")
@available(
*,
deprecated,
message:
"please use writeWithUnsafeMutableBytes(minimumWritableBytes:_:) instead to ensure sufficient write capacity."
)
@discardableResult
@inlinable
public mutating func writeWithUnsafeMutableBytes(_ body: (UnsafeMutableRawBufferPointer) throws -> Int) rethrows -> Int {
return try self.writeWithUnsafeMutableBytes(minimumWritableBytes: 0, { try body($0) })
public mutating func writeWithUnsafeMutableBytes(
_ body: (UnsafeMutableRawBufferPointer) throws -> Int
) rethrows -> Int {
try self.writeWithUnsafeMutableBytes(minimumWritableBytes: 0, { try body($0) })
}
/// This vends a pointer to the storage of the `ByteBuffer`. It's marked as _very unsafe_ because it might contain
@@ -677,7 +717,7 @@ public struct ByteBuffer {
/// - warning: Do not escape the pointer from the closure for later use.
@inlinable
public func withVeryUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
return try body(.init(self._slicedStorageBuffer))
try body(.init(self._slicedStorageBuffer))
}
/// This vends a pointer to the storage of the `ByteBuffer`. It's marked as _very unsafe_ because it might contain
@@ -685,8 +725,10 @@ public struct ByteBuffer {
///
/// - warning: Do not escape the pointer from the closure for later use.
@inlinable
public mutating func withVeryUnsafeMutableBytes<T>(_ body: (UnsafeMutableRawBufferPointer) throws -> T) rethrows -> T {
self._copyStorageAndRebaseIfNeeded() // this will trigger a CoW if necessary
public mutating func withVeryUnsafeMutableBytes<T>(
_ body: (UnsafeMutableRawBufferPointer) throws -> T
) rethrows -> T {
self._copyStorageAndRebaseIfNeeded() // this will trigger a CoW if necessary
return try body(.init(self._slicedStorageBuffer))
}
@@ -716,7 +758,9 @@ public struct ByteBuffer {
/// - body: The closure that will accept the yielded bytes and the `storageManagement`.
/// - returns: The value returned by `body`.
@inlinable
public func withUnsafeReadableBytesWithStorageManagement<T>(_ body: (UnsafeRawBufferPointer, Unmanaged<AnyObject>) throws -> T) rethrows -> T {
public func withUnsafeReadableBytesWithStorageManagement<T>(
_ body: (UnsafeRawBufferPointer, Unmanaged<AnyObject>) throws -> T
) rethrows -> T {
let storageReference: Unmanaged<AnyObject> = Unmanaged.passUnretained(self._storage)
// This is safe, writerIndex >= readerIndex
let range = Range<Int>(uncheckedBounds: (lower: self.readerIndex, upper: self.writerIndex))
@@ -725,7 +769,9 @@ public struct ByteBuffer {
/// See `withUnsafeReadableBytesWithStorageManagement` and `withVeryUnsafeBytes`.
@inlinable
public func withVeryUnsafeBytesWithStorageManagement<T>(_ body: (UnsafeRawBufferPointer, Unmanaged<AnyObject>) throws -> T) rethrows -> T {
public func withVeryUnsafeBytesWithStorageManagement<T>(
_ body: (UnsafeRawBufferPointer, Unmanaged<AnyObject>) throws -> T
) rethrows -> T {
let storageReference: Unmanaged<AnyObject> = Unmanaged.passUnretained(self._storage)
return try body(.init(self._slicedStorageBuffer), storageReference)
}
@@ -754,13 +800,16 @@ public struct ByteBuffer {
/// not readable in the initial `ByteBuffer`.
@inlinable
public func getSlice(at index: Int, length: Int) -> ByteBuffer? {
return self.getSlice_inlineAlways(at: index, length: length)
self.getSlice_inlineAlways(at: index, length: length)
}
@inline(__always)
@inlinable
internal func getSlice_inlineAlways(at index: Int, length: Int) -> ByteBuffer? {
guard index >= 0 && length >= 0 && index >= self.readerIndex && length <= self.writerIndex && index <= self.writerIndex &- length else {
guard
index >= 0 && length >= 0 && index >= self.readerIndex && length <= self.writerIndex
&& index <= self.writerIndex &- length
else {
return nil
}
let index = _toIndex(index)
@@ -789,8 +838,14 @@ public struct ByteBuffer {
// 2. `length` <= `self.writerIndex` (see `guard`s)
// 3. `sliceStartIndex` + `self._slice.count` is always safe (because that's `self._slice.upperBound`.
// - The range construction is safe because `length` >= 0 (see `guard` at the beginning of the function).
new._slice = _ByteBufferSlice(Range(uncheckedBounds: (lower: sliceStartIndex,
upper: sliceStartIndex &+ length)))
new._slice = _ByteBufferSlice(
Range(
uncheckedBounds: (
lower: sliceStartIndex,
upper: sliceStartIndex &+ length
)
)
)
new._moveReaderIndex(to: 0)
new._moveWriterIndex(to: length)
return new
@@ -815,8 +870,10 @@ public struct ByteBuffer {
if isKnownUniquelyReferenced(&self._storage) {
self._storage.bytes.advanced(by: Int(self._slice.lowerBound))
.copyMemory(from: self._storage.bytes.advanced(by: Int(self._slice.lowerBound + self._readerIndex)),
byteCount: self.readableBytes)
.copyMemory(
from: self._storage.bytes.advanced(by: Int(self._slice.lowerBound + self._readerIndex)),
byteCount: self.readableBytes
)
let indexShift = self._readerIndex
self._moveReaderIndex(to: 0)
self._moveWriterIndex(to: self._writerIndex - indexShift)
@@ -830,14 +887,14 @@ public struct ByteBuffer {
/// newly allocated `ByteBuffer`.
@inlinable
public var readerIndex: Int {
return Int(self._readerIndex)
Int(self._readerIndex)
}
/// The write index or the number of bytes previously written to this `ByteBuffer`. `writerIndex` is `0` for a
/// newly allocated `ByteBuffer`.
@inlinable
public var writerIndex: Int {
return Int(self._writerIndex)
Int(self._writerIndex)
}
/// Set both reader index and writer index to `0`. This will reset the state of this `ByteBuffer` to the state
@@ -869,7 +926,7 @@ public struct ByteBuffer {
public mutating func clear(minimumCapacity: UInt32) {
self.clear(minimumCapacity: Int(minimumCapacity))
}
/// Set both reader index and writer index to `0`. This will reset the state of this `ByteBuffer` to the state
/// of a freshly allocated one, if possible without allocations. This is the cheapest way to recycle a `ByteBuffer`
/// for a new use-case.
@@ -883,7 +940,7 @@ public struct ByteBuffer {
public mutating func clear(minimumCapacity: Int) {
precondition(minimumCapacity >= 0, "Cannot have a minimum capacity < 0")
precondition(minimumCapacity <= _Capacity.max, "Minimum capacity must be <= \(_Capacity.max)")
let minimumCapacity = _Capacity(minimumCapacity)
if !isKnownUniquelyReferenced(&self._storage) {
self._storage = self._storage.allocateStorage(capacity: minimumCapacity)
@@ -906,7 +963,7 @@ extension ByteBuffer: CustomStringConvertible, CustomDebugStringConvertible {
///
/// - returns: A description of this `ByteBuffer`.
public var description: String {
return """
"""
ByteBuffer { \
readerIndex: \(self.readerIndex), \
writerIndex: \(self.writerIndex), \
@@ -928,24 +985,24 @@ extension ByteBuffer: CustomStringConvertible, CustomDebugStringConvertible {
///
/// - returns: A description of this `ByteBuffer` useful for debugging.
public var debugDescription: String {
return "\(self.description)\nreadable bytes (max 1k): \(self._storage.dumpBytes(slice: self._slice, offset: self.readerIndex, length: min(1024, self.readableBytes)))"
"\(self.description)\nreadable bytes (max 1k): \(self._storage.dumpBytes(slice: self._slice, offset: self.readerIndex, length: min(1024, self.readableBytes)))"
}
}
/* change types to the user visible `Int` */
// change types to the user visible `Int`
extension ByteBuffer {
/// Copy the collection of `bytes` into the `ByteBuffer` at `index`. Does not move the writer index.
@discardableResult
@inlinable
public mutating func setBytes<Bytes: Sequence>(_ bytes: Bytes, at index: Int) -> Int where Bytes.Element == UInt8 {
return Int(self._setBytes(bytes, at: _toIndex(index)))
Int(self._setBytes(bytes, at: _toIndex(index)))
}
/// Copy `bytes` into the `ByteBuffer` at `index`. Does not move the writer index.
@discardableResult
@inlinable
public mutating func setBytes(_ bytes: UnsafeRawBufferPointer, at index: Int) -> Int {
return Int(self._setBytes(bytes, at: _toIndex(index)))
Int(self._setBytes(bytes, at: _toIndex(index)))
}
/// Move the reader index forward by `offset` bytes.
@@ -958,7 +1015,10 @@ extension ByteBuffer {
@inlinable
public mutating func moveReaderIndex(forwardBy offset: Int) {
let newIndex = self._readerIndex + _toIndex(offset)
precondition(newIndex >= 0 && newIndex <= writerIndex, "new readerIndex: \(newIndex), expected: range(0, \(writerIndex))")
precondition(
newIndex >= 0 && newIndex <= writerIndex,
"new readerIndex: \(newIndex), expected: range(0, \(writerIndex))"
)
self._moveReaderIndex(to: newIndex)
}
@@ -972,7 +1032,10 @@ extension ByteBuffer {
@inlinable
public mutating func moveReaderIndex(to offset: Int) {
let newIndex = _toIndex(offset)
precondition(newIndex >= 0 && newIndex <= writerIndex, "new readerIndex: \(newIndex), expected: range(0, \(writerIndex))")
precondition(
newIndex >= 0 && newIndex <= writerIndex,
"new readerIndex: \(newIndex), expected: range(0, \(writerIndex))"
)
self._moveReaderIndex(to: newIndex)
}
@@ -986,7 +1049,10 @@ extension ByteBuffer {
@inlinable
public mutating func moveWriterIndex(forwardBy offset: Int) {
let newIndex = self._writerIndex + _toIndex(offset)
precondition(newIndex >= 0 && newIndex <= _toCapacity(self._slice.count),"new writerIndex: \(newIndex), expected: range(0, \(_toCapacity(self._slice.count)))")
precondition(
newIndex >= 0 && newIndex <= _toCapacity(self._slice.count),
"new writerIndex: \(newIndex), expected: range(0, \(_toCapacity(self._slice.count)))"
)
self._moveWriterIndex(to: newIndex)
}
@@ -1000,7 +1066,10 @@ extension ByteBuffer {
@inlinable
public mutating func moveWriterIndex(to offset: Int) {
let newIndex = _toIndex(offset)
precondition(newIndex >= 0 && newIndex <= _toCapacity(self._slice.count),"new writerIndex: \(newIndex), expected: range(0, \(_toCapacity(self._slice.count)))")
precondition(
newIndex >= 0 && newIndex <= _toCapacity(self._slice.count),
"new writerIndex: \(newIndex), expected: range(0, \(_toCapacity(self._slice.count)))"
)
self._moveWriterIndex(to: newIndex)
}
}
@@ -1061,11 +1130,11 @@ extension ByteBuffer {
}
}
extension ByteBuffer.CopyBytesError: Hashable { }
extension ByteBuffer.CopyBytesError: Hashable {}
extension ByteBuffer.CopyBytesError: CustomDebugStringConvertible {
public var debugDescription: String {
return String(describing: self.baseError)
String(describing: self.baseError)
}
}
@@ -1074,7 +1143,7 @@ extension ByteBuffer: Equatable {
/// Compare two `ByteBuffer` values. Two `ByteBuffer` values are considered equal if the readable bytes are equal.
@inlinable
public static func ==(lhs: ByteBuffer, rhs: ByteBuffer) -> Bool {
public static func == (lhs: ByteBuffer, rhs: ByteBuffer) -> Bool {
guard lhs.readableBytes == rhs.readableBytes else {
return false
}
@@ -1143,7 +1212,7 @@ extension ByteBuffer {
return nil
}
let upperBound = indexFromReaderIndex &+ length // safe, can't overflow, we checked it above.
let upperBound = indexFromReaderIndex &+ length // safe, can't overflow, we checked it above.
// uncheckedBounds is safe because `length` is >= 0, so the lower bound will always be lower/equal to upper
return Range<Int>(uncheckedBounds: (lower: indexFromReaderIndex, upper: upperBound))
+3 -4
View File
@@ -131,7 +131,7 @@ extension ByteBuffer {
result += String(repeating: " ", count: 60 - result.count)
// Right column renders the 16 bytes line as ASCII characters, or "." if the character is not printable.
let printableRange = UInt8(ascii: " ") ..< UInt8(ascii: "~")
let printableRange = UInt8(ascii: " ")..<UInt8(ascii: "~")
let printableBytes = self.readableBytesView.map {
printableRange.contains($0) ? $0 : UInt8(ascii: ".")
}
@@ -183,7 +183,7 @@ extension ByteBuffer {
// reserve capacity for the maxBytes dumped, plus the separator line, and buffer length line.
var result = ""
result.reserveCapacity(maxBytes/16 * 79 + 79 + 8)
result.reserveCapacity(maxBytes / 16 * 79 + 79 + 8)
var buffer = self
@@ -246,7 +246,7 @@ extension ByteBuffer {
/// - parameters:
/// - format: ``HexDumpFormat`` to use for the dump.
public func hexDump(format: HexDumpFormat) -> String {
switch(format.value) {
switch format.value {
case .plain(let maxBytes):
if let maxBytes = maxBytes {
return self.hexDumpPlain(maxBytes: maxBytes)
@@ -263,4 +263,3 @@ extension ByteBuffer {
}
}
}
+18 -9
View File
@@ -14,7 +14,7 @@
extension ByteBuffer {
@inlinable
func _toEndianness<T: FixedWidthInteger> (value: T, endianness: Endianness) -> T {
func _toEndianness<T: FixedWidthInteger>(value: T, endianness: Endianness) -> T {
switch endianness {
case .little:
return value.littleEndian
@@ -48,7 +48,11 @@ extension ByteBuffer {
/// - returns: An integer value deserialized from this `ByteBuffer` or `nil` if the bytes of interest are not
/// readable.
@inlinable
public func getInteger<T: FixedWidthInteger>(at index: Int, endianness: Endianness = Endianness.big, as: T.Type = T.self) -> T? {
public func getInteger<T: FixedWidthInteger>(
at index: Int,
endianness: Endianness = Endianness.big,
as: T.Type = T.self
) -> T? {
guard let range = self.rangeWithinReadableBytes(index: index, length: MemoryLayout<T>.size) else {
return nil
}
@@ -78,9 +82,11 @@ extension ByteBuffer {
/// - returns: The number of bytes written.
@discardableResult
@inlinable
public mutating func writeInteger<T: FixedWidthInteger>(_ integer: T,
endianness: Endianness = .big,
as: T.Type = T.self) -> Int {
public mutating func writeInteger<T: FixedWidthInteger>(
_ integer: T,
endianness: Endianness = .big,
as: T.Type = T.self
) -> Int {
let bytesWritten = self.setInteger(integer, at: self.writerIndex, endianness: endianness)
self._moveWriterIndex(forwardBy: bytesWritten)
return Int(bytesWritten)
@@ -96,7 +102,12 @@ extension ByteBuffer {
/// - returns: The number of bytes written.
@discardableResult
@inlinable
public mutating func setInteger<T: FixedWidthInteger>(_ integer: T, at index: Int, endianness: Endianness = .big, as: T.Type = T.self) -> Int {
public mutating func setInteger<T: FixedWidthInteger>(
_ integer: T,
at index: Int,
endianness: Endianness = .big,
as: T.Type = T.self
) -> Int {
var value = _toEndianness(value: integer, endianness: endianness)
return Swift.withUnsafeBytes(of: &value) { ptr in
self.setBytes(ptr, at: index)
@@ -166,7 +177,7 @@ public enum Endianness: Sendable {
public static let host: Endianness = hostEndianness0()
private static func hostEndianness0() -> Endianness {
let number: UInt32 = 0x12345678
let number: UInt32 = 0x1234_5678
return number == number.bigEndian ? .big : .little
}
@@ -176,5 +187,3 @@ public enum Endianness: Sendable {
/// little endian, the least significant byte (LSB) is at the lowest address
case little
}
+29 -24
View File
@@ -19,9 +19,13 @@ extension ByteBuffer {
case messageCouldNotBeReadSuccessfully
}
private var baseError: BaseError
public static let messageLengthDoesNotFitExactlyIntoRequiredIntegerFormat: LengthPrefixError = .init(baseError: .messageLengthDoesNotFitExactlyIntoRequiredIntegerFormat)
public static let messageCouldNotBeReadSuccessfully: LengthPrefixError = .init(baseError: .messageCouldNotBeReadSuccessfully)
public static let messageLengthDoesNotFitExactlyIntoRequiredIntegerFormat: LengthPrefixError = .init(
baseError: .messageLengthDoesNotFitExactlyIntoRequiredIntegerFormat
)
public static let messageCouldNotBeReadSuccessfully: LengthPrefixError = .init(
baseError: .messageCouldNotBeReadSuccessfully
)
}
}
@@ -41,44 +45,44 @@ extension ByteBuffer {
writeMessage: (inout ByteBuffer) throws -> Int
) throws -> Int where Integer: FixedWidthInteger {
var totalBytesWritten = 0
let lengthPrefixIndex = self.writerIndex
// Write a zero as a placeholder which will later be overwritten by the actual number of bytes written
totalBytesWritten += self.writeInteger(.zero, endianness: endianness, as: Integer.self)
let startWriterIndex = self.writerIndex
let messageLength = try writeMessage(&self)
let endWriterIndex = self.writerIndex
totalBytesWritten += messageLength
let actualBytesWritten = endWriterIndex - startWriterIndex
assert(
actualBytesWritten == messageLength,
actualBytesWritten == messageLength,
"writeMessage returned \(messageLength) bytes, but actually \(actualBytesWritten) bytes were written, but they should be the same"
)
guard let lengthPrefix = Integer(exactly: messageLength) else {
throw LengthPrefixError.messageLengthDoesNotFitExactlyIntoRequiredIntegerFormat
}
self.setInteger(lengthPrefix, at: lengthPrefixIndex, endianness: endianness, as: Integer.self)
return totalBytesWritten
}
}
extension ByteBuffer {
/// Reads an `Integer` from `self`, reads a slice of that length and passes it to `readMessage`.
/// Reads an `Integer` from `self`, reads a slice of that length and passes it to `readMessage`.
/// It is checked that `readMessage` returns a non-nil value.
///
///
/// The `readerIndex` is **not** moved forward if the length prefix could not be read or `self` does not contain enough bytes. Otherwise `readerIndex` is moved forward even if `readMessage` throws or returns nil.
/// - Parameters:
/// - endianness: The endianness of the length prefix `Integer` in this `ByteBuffer` (defaults to big endian).
/// - integer: the desired `Integer` type used to read the length prefix
/// - readMessage: A closure that takes a `ByteBuffer` slice which contains the message after the length prefix
/// - Throws: if `readMessage` returns nil
/// - Returns: `nil` if the length prefix could not be read,
/// - Returns: `nil` if the length prefix could not be read,
/// the length prefix is negative or
/// the buffer does not contain enough bytes to read a message of this length.
/// Otherwise the result of `readMessage`.
@@ -96,14 +100,14 @@ extension ByteBuffer {
}
return result
}
/// Reads an `Integer` from `self` and reads a slice of that length from `self` and returns it.
///
///
/// If nil is returned, `readerIndex` is **not** moved forward.
/// - Parameters:
/// - endianness: The endianness of the length prefix `Integer` in this `ByteBuffer` (defaults to big endian).
/// - integer: the desired `Integer` type used to read the length prefix
/// - Returns: `nil` if the length prefix could not be read,
/// - Returns: `nil` if the length prefix could not be read,
/// the length prefix is negative or
/// the buffer does not contain enough bytes to read a message of this length.
/// Otherwise the message after the length prefix.
@@ -112,19 +116,20 @@ extension ByteBuffer {
endianness: Endianness = .big,
as integer: Integer.Type
) -> ByteBuffer? where Integer: FixedWidthInteger {
guard let result = self.getLengthPrefixedSlice(at: self.readerIndex, endianness: endianness, as: Integer.self) else {
guard let result = self.getLengthPrefixedSlice(at: self.readerIndex, endianness: endianness, as: Integer.self)
else {
return nil
}
self._moveReaderIndex(forwardBy: MemoryLayout<Integer>.size + result.readableBytes)
return result
}
/// Gets an `Integer` from `self` and gets a slice of that length from `self` and returns it.
///
///
/// - Parameters:
/// - endianness: The endianness of the length prefix `Integer` in this `ByteBuffer` (defaults to big endian).
/// - integer: the desired `Integer` type used to get the length prefix
/// - Returns: `nil` if the length prefix could not be read,
/// - Returns: `nil` if the length prefix could not be read,
/// the length prefix is negative or
/// the buffer does not contain enough bytes to read a message of this length.
/// Otherwise the message after the length prefix.
@@ -135,12 +140,12 @@ extension ByteBuffer {
as integer: Integer.Type
) -> ByteBuffer? where Integer: FixedWidthInteger {
guard let lengthPrefix = self.getInteger(at: index, endianness: endianness, as: Integer.self),
let messageLength = Int(exactly: lengthPrefix),
let messageBuffer = self.getSlice(at: index + MemoryLayout<Integer>.size, length: messageLength)
let messageLength = Int(exactly: lengthPrefix),
let messageBuffer = self.getSlice(at: index + MemoryLayout<Integer>.size, length: messageLength)
else {
return nil
}
return messageBuffer
}
}
File diff suppressed because it is too large Load Diff
+61 -44
View File
@@ -21,8 +21,8 @@ public struct ByteBufferView: RandomAccessCollection, Sendable {
public typealias Index = Int
public typealias SubSequence = ByteBufferView
/* private but usableFromInline */ @usableFromInline var _buffer: ByteBuffer
/* private but usableFromInline */ @usableFromInline var _range: Range<Index>
@usableFromInline var _buffer: ByteBuffer
@usableFromInline var _range: Range<Index>
@inlinable
internal init(buffer: ByteBuffer, range: Range<Index>) {
@@ -34,37 +34,41 @@ public struct ByteBufferView: RandomAccessCollection, Sendable {
/// Creates a `ByteBufferView` from the readable bytes of the given `buffer`.
@inlinable
public init(_ buffer: ByteBuffer) {
self = ByteBufferView(buffer: buffer, range: buffer.readerIndex ..< buffer.writerIndex)
self = ByteBufferView(buffer: buffer, range: buffer.readerIndex..<buffer.writerIndex)
}
@inlinable
public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
return try self._buffer.withVeryUnsafeBytes { ptr in
try body(UnsafeRawBufferPointer(start: ptr.baseAddress!.advanced(by: self._range.lowerBound),
count: self._range.count))
try self._buffer.withVeryUnsafeBytes { ptr in
try body(
UnsafeRawBufferPointer(
start: ptr.baseAddress!.advanced(by: self._range.lowerBound),
count: self._range.count
)
)
}
}
@inlinable
public var startIndex: Index {
return self._range.lowerBound
self._range.lowerBound
}
@inlinable
public var endIndex: Index {
return self._range.upperBound
self._range.upperBound
}
@inlinable
public func index(after i: Index) -> Index {
return i + 1
i + 1
}
@inlinable
public var count: Int {
// Unchecked is safe here: Range enforces that upperBound is strictly greater than
// lower bound, and we guarantee that _range.lowerBound >= 0.
return self._range.upperBound &- self._range.lowerBound
self._range.upperBound &- self._range.lowerBound
}
@inlinable
@@ -73,7 +77,7 @@ public struct ByteBufferView: RandomAccessCollection, Sendable {
guard position >= self._range.lowerBound && position < self._range.upperBound else {
preconditionFailure("index \(position) out of range")
}
return self._buffer.getInteger(at: position)! // range check above
return self._buffer.getInteger(at: position)! // range check above
}
set {
guard position >= self._range.lowerBound && position < self._range.upperBound else {
@@ -86,7 +90,7 @@ public struct ByteBufferView: RandomAccessCollection, Sendable {
@inlinable
public subscript(range: Range<Index>) -> ByteBufferView {
get {
return ByteBufferView(buffer: self._buffer, range: range)
ByteBufferView(buffer: self._buffer, range: range)
}
set {
self.replaceSubrange(range, with: newValue)
@@ -95,35 +99,41 @@ public struct ByteBufferView: RandomAccessCollection, Sendable {
@inlinable
public func withContiguousStorageIfAvailable<R>(_ body: (UnsafeBufferPointer<UInt8>) throws -> R) rethrows -> R? {
return try self.withUnsafeBytes { bytes in
return try body(bytes.bindMemory(to: UInt8.self))
try self.withUnsafeBytes { bytes in
try body(bytes.bindMemory(to: UInt8.self))
}
}
@inlinable
public func _customIndexOfEquatableElement(_ element : Element) -> Index?? {
return .some(self.withUnsafeBytes { ptr -> Index? in
return ptr.firstIndex(of: element).map { $0 + self._range.lowerBound }
})
public func _customIndexOfEquatableElement(_ element: Element) -> Index?? {
.some(
self.withUnsafeBytes { ptr -> Index? in
ptr.firstIndex(of: element).map { $0 + self._range.lowerBound }
}
)
}
@inlinable
public func _customLastIndexOfEquatableElement(_ element: Element) -> Index?? {
return .some(self.withUnsafeBytes { ptr -> Index? in
return ptr.lastIndex(of: element).map { $0 + self._range.lowerBound }
})
.some(
self.withUnsafeBytes { ptr -> Index? in
ptr.lastIndex(of: element).map { $0 + self._range.lowerBound }
}
)
}
@inlinable
public func _customContainsEquatableElement(_ element: Element) -> Bool? {
return .some(self.withUnsafeBytes { ptr -> Bool in
return ptr.contains(element)
})
.some(
self.withUnsafeBytes { ptr -> Bool in
ptr.contains(element)
}
)
}
@inlinable
public func _copyContents(
initializing ptr: UnsafeMutableBufferPointer<UInt8>
initializing ptr: UnsafeMutableBufferPointer<UInt8>
) -> (Iterator, UnsafeMutableBufferPointer<UInt8>.Index) {
precondition(ptr.count >= self.count)
@@ -141,10 +151,10 @@ public struct ByteBufferView: RandomAccessCollection, Sendable {
// These are implemented as no-ops for performance reasons.
@inlinable
public func _failEarlyRangeCheck(_ index: Index, bounds: Range<Index>) {}
@inlinable
public func _failEarlyRangeCheck(_ index: Index, bounds: ClosedRange<Index>) {}
@inlinable
public func _failEarlyRangeCheck(_ range: Range<Index>, bounds: Range<Index>) {}
}
@@ -176,7 +186,7 @@ extension ByteBufferView: RangeReplaceableCollection {
// ``CollectionOfOne`` has no witness for
// ``Sequence.withContiguousStorageIfAvailable(_:)``. so we do this instead:
self._buffer.setInteger(byte, at: self._range.upperBound)
self._range = self._range.lowerBound ..< self._range.upperBound.advanced(by: 1)
self._range = self._range.lowerBound..<self._range.upperBound.advanced(by: 1)
self._buffer.moveWriterIndex(to: self._range.upperBound)
}
@@ -184,14 +194,17 @@ extension ByteBufferView: RangeReplaceableCollection {
@inlinable
public mutating func append<Bytes: Sequence>(contentsOf bytes: Bytes) where Bytes.Element == UInt8 {
let written = self._buffer.setBytes(bytes, at: self._range.upperBound)
self._range = self._range.lowerBound ..< self._range.upperBound.advanced(by: written)
self._range = self._range.lowerBound..<self._range.upperBound.advanced(by: written)
self._buffer.moveWriterIndex(to: self._range.upperBound)
}
@inlinable
public mutating func replaceSubrange<C: Collection>(_ subrange: Range<Index>, with newElements: C) where ByteBufferView.Element == C.Element {
precondition(subrange.startIndex >= self.startIndex && subrange.endIndex <= self.endIndex,
"subrange out of bounds")
public mutating func replaceSubrange<C: Collection>(_ subrange: Range<Index>, with newElements: C)
where ByteBufferView.Element == C.Element {
precondition(
subrange.startIndex >= self.startIndex && subrange.endIndex <= self.endIndex,
"subrange out of bounds"
)
if newElements.count == subrange.count {
self._buffer.setBytes(newElements, at: subrange.startIndex)
@@ -201,9 +214,11 @@ extension ByteBufferView: RangeReplaceableCollection {
// Remove the unwanted bytes between the newly copied bytes and the end of the subrange.
// try! is fine here: the copied range is within the view and the length can't be negative.
try! self._buffer.copyBytes(at: subrange.endIndex,
to: subrange.startIndex.advanced(by: newElements.count),
length: subrange.endIndex.distance(to: self._buffer.writerIndex))
try! self._buffer.copyBytes(
at: subrange.endIndex,
to: subrange.startIndex.advanced(by: newElements.count),
length: subrange.endIndex.distance(to: self._buffer.writerIndex)
)
// Shorten the range.
let removedBytes = subrange.count - newElements.count
@@ -212,9 +227,11 @@ extension ByteBufferView: RangeReplaceableCollection {
} else {
// Make space for the new elements.
// try! is fine here: the copied range is within the view and the length can't be negative.
try! self._buffer.copyBytes(at: subrange.endIndex,
to: subrange.startIndex.advanced(by: newElements.count),
length: subrange.endIndex.distance(to: self._buffer.writerIndex))
try! self._buffer.copyBytes(
at: subrange.endIndex,
to: subrange.startIndex.advanced(by: newElements.count),
length: subrange.endIndex.distance(to: self._buffer.writerIndex)
)
// Replace the bytes.
self._buffer.setBytes(newElements, at: subrange.startIndex)
@@ -222,7 +239,7 @@ extension ByteBufferView: RangeReplaceableCollection {
// Widen the range.
let additionalByteCount = newElements.count - subrange.count
self._buffer.moveWriterIndex(forwardBy: additionalByteCount)
self._range = self._range.startIndex ..< self._range.endIndex.advanced(by: additionalByteCount)
self._range = self._range.startIndex..<self._range.endIndex.advanced(by: additionalByteCount)
}
}
}
@@ -231,7 +248,7 @@ extension ByteBuffer {
/// A view into the readable bytes of the `ByteBuffer`.
@inlinable
public var readableBytesView: ByteBufferView {
return ByteBufferView(self)
ByteBufferView(self)
}
/// Returns a view into some portion of the readable bytes of a `ByteBuffer`.
@@ -246,7 +263,7 @@ extension ByteBuffer {
return nil
}
return ByteBufferView(buffer: self, range: index ..< (index + length))
return ByteBufferView(buffer: self, range: index..<(index + length))
}
/// Create a `ByteBuffer` from the given `ByteBufferView`s range.
@@ -264,14 +281,14 @@ extension ByteBufferView: Equatable {
public static func == (lhs: ByteBufferView, rhs: ByteBufferView) -> Bool {
guard lhs._range.count == rhs._range.count else {
return false
return false
}
// A well-formed ByteBufferView can never have a range that is out-of-bounds of the backing ByteBuffer.
// As a result, these getSlice calls can never fail, and we'd like to know it if they do.
let leftBufferSlice = lhs._buffer.getSlice(at: lhs._range.startIndex, length: lhs._range.count)!
let rightBufferSlice = rhs._buffer.getSlice(at: rhs._range.startIndex, length: rhs._range.count)!
return leftBufferSlice == rightBufferSlice
}
}
+6 -8
View File
@@ -150,7 +150,7 @@ public protocol Channel: AnyObject, ChannelOutboundInvoker, _NIOPreconcurrencySe
extension Channel {
/// Default implementation: `NIOSynchronousChannelOptions` are not supported.
public var syncOptions: NIOSynchronousChannelOptions? {
return nil
nil
}
}
@@ -210,7 +210,6 @@ extension Channel {
}
}
/// Provides special extension to make writing data to the `Channel` easier by removing the need to wrap data in `NIOAny` manually.
extension Channel {
@@ -218,7 +217,7 @@ extension Channel {
///
/// - seealso: `ChannelOutboundInvoker.write`.
public func write<T>(_ any: T) -> EventLoopFuture<Void> {
return self.write(NIOAny(any))
self.write(NIOAny(any))
}
/// Write data into the `Channel`, automatically wrapping with `NIOAny`.
@@ -232,10 +231,9 @@ extension Channel {
///
/// - seealso: `ChannelOutboundInvoker.writeAndFlush`.
public func writeAndFlush<T>(_ any: T) -> EventLoopFuture<Void> {
return self.writeAndFlush(NIOAny(any))
self.writeAndFlush(NIOAny(any))
}
/// Write and flush data into the `Channel`, automatically wrapping with `NIOAny`.
///
/// - seealso: `ChannelOutboundInvoker.writeAndFlush`.
@@ -262,7 +260,7 @@ extension ChannelCore {
/// - returns: The content of the `NIOAny`.
@inlinable
public func unwrapData<T>(_ data: NIOAny, as: T.Type = T.self) -> T {
return data.forceAs()
data.forceAs()
}
/// Attempts to unwrap the given `NIOAny` as a specific concrete type.
@@ -284,7 +282,7 @@ extension ChannelCore {
/// are doing something _extremely_ unusual.
@inlinable
public func tryUnwrapData<T>(_ data: NIOAny, as: T.Type = T.self) -> T? {
return data.tryAs()
data.tryAs()
}
/// Removes the `ChannelHandler`s from the `ChannelPipeline` belonging to `channel`, and
@@ -384,7 +382,7 @@ extension ChannelError {
static let _unremovableHandler: any Error = ChannelError.unremovableHandler
}
extension ChannelError: Equatable { }
extension ChannelError: Equatable {}
/// The removal of a `ChannelHandler` using `ChannelPipeline.removeHandler` has been attempted more than once.
public struct NIOAttemptedToRemoveHandlerMultipleTimesError: Error {}
+48 -23
View File
@@ -15,7 +15,6 @@
//
//
/// A `ChannelHandler` that implements a backoff for a `ServerChannel` when accept produces an `IOError`.
/// These errors are often recoverable by reducing the rate at which we call accept.
public final class AcceptBackoffHandler: ChannelDuplexHandler, RemovableChannelHandler {
@@ -28,7 +27,7 @@ public final class AcceptBackoffHandler: ChannelDuplexHandler, RemovableChannelH
/// Default implementation used as `backoffProvider` which delays accept by 1 second.
public static func defaultBackoffProvider(error: IOError) -> TimeAmount? {
return .seconds(1)
.seconds(1)
}
/// Create a new instance
@@ -108,10 +107,8 @@ public final class AcceptBackoffHandler: ChannelDuplexHandler, RemovableChannelH
@available(*, unavailable)
extension AcceptBackoffHandler: Sendable {}
/**
ChannelHandler implementation which enforces back-pressure by stopping to read from the remote peer when it cannot write back fast enough.
It will start reading again once pending data was written.
*/
/// ChannelHandler implementation which enforces back-pressure by stopping to read from the remote peer when it cannot write back fast enough.
/// It will start reading again once pending data was written.
public final class BackPressureHandler: ChannelDuplexHandler, RemovableChannelHandler {
public typealias OutboundIn = NIOAny
public typealias InboundIn = ByteBuffer
@@ -121,7 +118,7 @@ public final class BackPressureHandler: ChannelDuplexHandler, RemovableChannelHa
private var pendingRead = false
private var writable: Bool = true
public init() { }
public init() {}
public func read(context: ChannelHandlerContext) {
if writable {
@@ -218,7 +215,7 @@ public final class IdleStateHandler: ChannelDuplexHandler, RemovableChannelHandl
}
public func channelReadComplete(context: ChannelHandlerContext) {
if (readTimeout != nil || allTimeout != nil) && reading {
if (readTimeout != nil || allTimeout != nil) && reading {
lastReadTime = .now()
reading = false
}
@@ -246,32 +243,41 @@ public final class IdleStateHandler: ChannelDuplexHandler, RemovableChannelHandl
}
private func makeReadTimeoutTask(_ context: ChannelHandlerContext, _ timeout: TimeAmount) -> (() -> Void) {
return {
guard self.shouldReschedule(context) else {
{
guard self.shouldReschedule(context) else {
return
}
if self.reading {
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(in: timeout, self.makeReadTimeoutTask(context, timeout))
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(
in: timeout,
self.makeReadTimeoutTask(context, timeout)
)
return
}
let diff = .now() - self.lastReadTime
if diff >= timeout {
// Reader is idle - set a new timeout and trigger an event through the pipeline
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(in: timeout, self.makeReadTimeoutTask(context, timeout))
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(
in: timeout,
self.makeReadTimeoutTask(context, timeout)
)
context.fireUserInboundEventTriggered(IdleStateEvent.read)
} else {
// Read occurred before the timeout - set a new timeout with shorter delay.
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(deadline: self.lastReadTime + timeout, self.makeReadTimeoutTask(context, timeout))
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(
deadline: self.lastReadTime + timeout,
self.makeReadTimeoutTask(context, timeout)
)
}
}
}
private func makeWriteTimeoutTask(_ context: ChannelHandlerContext, _ timeout: TimeAmount) -> (() -> Void) {
return {
guard self.shouldReschedule(context) else {
{
guard self.shouldReschedule(context) else {
return
}
@@ -280,24 +286,33 @@ public final class IdleStateHandler: ChannelDuplexHandler, RemovableChannelHandl
if diff >= timeout {
// Writer is idle - set a new timeout and notify the callback.
self.scheduledWriterTask = context.eventLoop.assumeIsolated().scheduleTask(in: timeout, self.makeWriteTimeoutTask(context, timeout))
self.scheduledWriterTask = context.eventLoop.assumeIsolated().scheduleTask(
in: timeout,
self.makeWriteTimeoutTask(context, timeout)
)
context.fireUserInboundEventTriggered(IdleStateEvent.write)
} else {
// Write occurred before the timeout - set a new timeout with shorter delay.
self.scheduledWriterTask = context.eventLoop.assumeIsolated().scheduleTask(deadline: self.lastWriteCompleteTime + timeout, self.makeWriteTimeoutTask(context, timeout))
self.scheduledWriterTask = context.eventLoop.assumeIsolated().scheduleTask(
deadline: self.lastWriteCompleteTime + timeout,
self.makeWriteTimeoutTask(context, timeout)
)
}
}
}
private func makeAllTimeoutTask(_ context: ChannelHandlerContext, _ timeout: TimeAmount) -> (() -> Void) {
return {
guard self.shouldReschedule(context) else {
{
guard self.shouldReschedule(context) else {
return
}
if self.reading {
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(in: timeout, self.makeAllTimeoutTask(context, timeout))
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(
in: timeout,
self.makeAllTimeoutTask(context, timeout)
)
return
}
let lastRead = self.lastReadTime
@@ -307,17 +322,27 @@ public final class IdleStateHandler: ChannelDuplexHandler, RemovableChannelHandl
let diff = .now() - latestLast
if diff >= timeout {
// Reader is idle - set a new timeout and trigger an event through the pipeline
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(in: timeout, self.makeAllTimeoutTask(context, timeout))
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(
in: timeout,
self.makeAllTimeoutTask(context, timeout)
)
context.fireUserInboundEventTriggered(IdleStateEvent.all)
} else {
// Read occurred before the timeout - set a new timeout with shorter delay.
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(deadline: latestLast + timeout, self.makeAllTimeoutTask(context, timeout))
self.scheduledReaderTask = context.eventLoop.assumeIsolated().scheduleTask(
deadline: latestLast + timeout,
self.makeAllTimeoutTask(context, timeout)
)
}
}
}
private func schedule(_ context: ChannelHandlerContext, _ amount: TimeAmount?, _ body: @escaping (ChannelHandlerContext, TimeAmount) -> (() -> Void) ) -> Scheduled<Void>? {
private func schedule(
_ context: ChannelHandlerContext,
_ amount: TimeAmount?,
_ body: @escaping (ChannelHandlerContext, TimeAmount) -> (() -> Void)
) -> Scheduled<Void>? {
if let timeout = amount {
return context.eventLoop.assumeIsolated().scheduleTask(in: timeout, body(context, timeout))
}
+21 -7
View File
@@ -103,7 +103,11 @@ extension ChannelOutboundInvoker {
/// - parameters:
/// - to: the `SocketAddress` to which we should bind the `Channel`.
/// - returns: the future which will be notified once the operation completes.
public func bind(to address: SocketAddress, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
public func bind(
to address: SocketAddress,
file: StaticString = #fileID,
line: UInt = #line
) -> EventLoopFuture<Void> {
let promise = makePromise(file: file, line: line)
bind(to: address, promise: promise)
return promise.futureResult
@@ -113,7 +117,11 @@ extension ChannelOutboundInvoker {
/// - parameters:
/// - to: the `SocketAddress` to which we should connect the `Channel`.
/// - returns: the future which will be notified once the operation completes.
public func connect(to address: SocketAddress, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
public func connect(
to address: SocketAddress,
file: StaticString = #fileID,
line: UInt = #line
) -> EventLoopFuture<Void> {
let promise = makePromise(file: file, line: line)
connect(to: address, promise: promise)
return promise.futureResult
@@ -138,7 +146,8 @@ extension ChannelOutboundInvoker {
/// - parameters:
/// - data: the data to write
/// - returns: the future which will be notified once the `write` operation completes.
public func writeAndFlush(_ data: NIOAny, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
public func writeAndFlush(_ data: NIOAny, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void>
{
let promise = makePromise(file: file, line: line)
writeAndFlush(data, promise: promise)
return promise.futureResult
@@ -149,7 +158,8 @@ extension ChannelOutboundInvoker {
/// - parameters:
/// - mode: the `CloseMode` that is used
/// - returns: the future which will be notified once the operation completes.
public func close(mode: CloseMode = .all, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
public func close(mode: CloseMode = .all, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void>
{
let promise = makePromise(file: file, line: line)
close(mode: mode, promise: promise)
return promise.futureResult
@@ -160,14 +170,18 @@ extension ChannelOutboundInvoker {
/// - parameters:
/// - event: the event itself.
/// - returns: the future which will be notified once the operation completes.
public func triggerUserOutboundEvent(_ event: Any, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Void> {
public func triggerUserOutboundEvent(
_ event: Any,
file: StaticString = #fileID,
line: UInt = #line
) -> EventLoopFuture<Void> {
let promise = makePromise(file: file, line: line)
triggerUserOutboundEvent(event, promise: promise)
return promise.futureResult
}
private func makePromise(file: StaticString = #fileID, line: UInt = #line) -> EventLoopPromise<Void> {
return eventLoop.makePromise(file: file, line: line)
eventLoop.makePromise(file: file, line: line)
}
}
@@ -228,7 +242,7 @@ public protocol ChannelInboundInvoker {
}
/// A protocol that signals that outbound and inbound events are triggered by this invoker.
public protocol ChannelInvoker: ChannelOutboundInvoker, ChannelInboundInvoker { }
public protocol ChannelInvoker: ChannelOutboundInvoker, ChannelInboundInvoker {}
/// Specify what kind of close operation is requested.
public enum CloseMode: Sendable {
+46 -28
View File
@@ -20,11 +20,11 @@ public protocol ChannelOption: Equatable, _NIOPreconcurrencySendable {
public typealias SocketOptionName = Int32
#if (os(Linux) || os(Android)) && !canImport(Musl)
public typealias SocketOptionLevel = Int
public typealias SocketOptionValue = Int
public typealias SocketOptionLevel = Int
public typealias SocketOptionValue = Int
#else
public typealias SocketOptionLevel = CInt
public typealias SocketOptionValue = CInt
public typealias SocketOptionLevel = CInt
public typealias SocketOptionValue = CInt
#endif
@available(*, deprecated, renamed: "ChannelOptions.Types.SocketOption")
@@ -77,7 +77,7 @@ extension ChannelOptions {
public var level: SocketOptionLevel {
get {
return SocketOptionLevel(optionLevel.rawValue)
SocketOptionLevel(optionLevel.rawValue)
}
set {
self.optionLevel = NIOBSDSocket.OptionLevel(rawValue: CInt(newValue))
@@ -85,7 +85,7 @@ extension ChannelOptions {
}
public var name: SocketOptionName {
get {
return SocketOptionName(optionName.rawValue)
SocketOptionName(optionName.rawValue)
}
set {
self.optionName = NIOBSDSocket.Option(rawValue: CInt(newValue))
@@ -93,15 +93,15 @@ extension ChannelOptions {
}
#if !os(Windows)
/// Create a new `SocketOption`.
///
/// - parameters:
/// - level: The level for the option as defined in `man setsockopt`, e.g. SO_SOCKET.
/// - name: The name of the option as defined in `man setsockopt`, e.g. `SO_REUSEADDR`.
public init(level: SocketOptionLevel, name: SocketOptionName) {
self.optionLevel = NIOBSDSocket.OptionLevel(rawValue: CInt(level))
self.optionName = NIOBSDSocket.Option(rawValue: CInt(name))
}
/// Create a new `SocketOption`.
///
/// - parameters:
/// - level: The level for the option as defined in `man setsockopt`, e.g. SO_SOCKET.
/// - name: The name of the option as defined in `man setsockopt`, e.g. `SO_REUSEADDR`.
public init(level: SocketOptionLevel, name: SocketOptionName) {
self.optionLevel = NIOBSDSocket.OptionLevel(rawValue: CInt(level))
self.optionName = NIOBSDSocket.Option(rawValue: CInt(name))
}
#endif
/// Create a new `SocketOption`.
@@ -188,7 +188,7 @@ extension ChannelOptions {
public struct DatagramVectorReadMessageCountOption: ChannelOption, Sendable {
public typealias Value = Int
public init() { }
public init() {}
}
/// ``DatagramSegmentSize`` controls the `UDP_SEGMENT` socket option (sometimes reffered to as 'GSO') which allows for
@@ -201,7 +201,7 @@ extension ChannelOptions {
/// Setting this option to zero disables segmentation offload.
public struct DatagramSegmentSize: ChannelOption, Sendable {
public typealias Value = CInt
public init() { }
public init() {}
}
/// ``DatagramReceiveOffload`` sets the `UDP_GRO` socket option which allows for datagrams to be accumulated
@@ -214,7 +214,7 @@ extension ChannelOptions {
/// The default allocator for datagram channels uses fixed sized buffers of 2048 bytes.
public struct DatagramReceiveOffload: ChannelOption, Sendable {
public typealias Value = Bool
public init() { }
public init() {}
}
/// When set to true IP level ECN information will be reported through `AddressedEnvelope.Metadata`
@@ -293,23 +293,27 @@ extension ChannelOptions {
/// Provides `ChannelOption`s to be used with a `Channel`, `Bootstrap` or `ServerBootstrap`.
public struct ChannelOptions: Sendable {
#if !os(Windows)
public static let socket: @Sendable (SocketOptionLevel, SocketOptionName) -> ChannelOptions.Types.SocketOption = { (level: SocketOptionLevel, name: SocketOptionName) -> Types.SocketOption in
.init(level: NIOBSDSocket.OptionLevel(rawValue: CInt(level)), name: NIOBSDSocket.Option(rawValue: CInt(name)))
}
public static let socket: @Sendable (SocketOptionLevel, SocketOptionName) -> ChannelOptions.Types.SocketOption = {
(level: SocketOptionLevel, name: SocketOptionName) -> Types.SocketOption in
.init(level: NIOBSDSocket.OptionLevel(rawValue: CInt(level)), name: NIOBSDSocket.Option(rawValue: CInt(name)))
}
#endif
/// - seealso: `SocketOption`.
public static let socketOption: @Sendable (NIOBSDSocket.Option) -> ChannelOptions.Types.SocketOption = { (name: NIOBSDSocket.Option) -> Types.SocketOption in
public static let socketOption: @Sendable (NIOBSDSocket.Option) -> ChannelOptions.Types.SocketOption = {
(name: NIOBSDSocket.Option) -> Types.SocketOption in
.init(level: .socket, name: name)
}
/// - seealso: `SocketOption`.
public static let ipOption: @Sendable (NIOBSDSocket.Option) -> ChannelOptions.Types.SocketOption = { (name: NIOBSDSocket.Option) -> Types.SocketOption in
public static let ipOption: @Sendable (NIOBSDSocket.Option) -> ChannelOptions.Types.SocketOption = {
(name: NIOBSDSocket.Option) -> Types.SocketOption in
.init(level: .ip, name: name)
}
/// - seealso: `SocketOption`.
public static let tcpOption: @Sendable (NIOBSDSocket.Option) -> ChannelOptions.Types.SocketOption = { (name: NIOBSDSocket.Option) -> Types.SocketOption in
public static let tcpOption: @Sendable (NIOBSDSocket.Option) -> ChannelOptions.Types.SocketOption = {
(name: NIOBSDSocket.Option) -> Types.SocketOption in
.init(level: .tcp, name: name)
}
@@ -361,7 +365,11 @@ extension ChannelOptions {
/// `Channel` that needs to store `ChannelOption`s.
public struct Storage: Sendable {
@usableFromInline
internal var _storage: [(any ChannelOption, (any Sendable, @Sendable (Channel) -> (any ChannelOption, any Sendable) -> EventLoopFuture<Void>))]
internal var _storage:
[(
any ChannelOption,
(any Sendable, @Sendable (Channel) -> (any ChannelOption, any Sendable) -> EventLoopFuture<Void>)
)]
public init() {
self._storage = []
@@ -377,8 +385,8 @@ extension ChannelOptions {
public mutating func append<Option: ChannelOption>(key newKey: Option, value newValue: Option.Value) {
@Sendable
func applier(_ t: Channel) -> (any ChannelOption, any Sendable) -> EventLoopFuture<Void> {
return { (option, value) in
return t.setOption(option as! Option, value: value as! Option.Value)
{ (option, value) in
t.setOption(option as! Option, value: value as! Option.Value)
}
}
var hasSet = false
@@ -407,7 +415,17 @@ extension ChannelOptions {
let it = self._storage.makeIterator()
@Sendable
func applyNext(iterator: IndexingIterator<[(any ChannelOption, (any Sendable, @Sendable (any Channel) -> (any ChannelOption, any Sendable) -> EventLoopFuture<Void>))]>) {
func applyNext(
iterator: IndexingIterator<
[(
any ChannelOption,
(
any Sendable,
@Sendable (any Channel) -> (any ChannelOption, any Sendable) -> EventLoopFuture<Void>
)
)]
>
) {
var iterator = iterator
guard let (key, (value, applier)) = iterator.next() else {
// If we reached the end, everything is applied.
+141 -90
View File
@@ -167,9 +167,11 @@ public final class ChannelPipeline: ChannelInvoker {
/// - handler: the `ChannelHandler` to add
/// - position: The position in the `ChannelPipeline` to add `handler`. Defaults to `.last`.
/// - returns: the `EventLoopFuture` which will be notified once the `ChannelHandler` was added.
public func addHandler(_ handler: ChannelHandler,
name: String? = nil,
position: ChannelPipeline.Position = .last) -> EventLoopFuture<Void> {
public func addHandler(
_ handler: ChannelHandler,
name: String? = nil,
position: ChannelPipeline.Position = .last
) -> EventLoopFuture<Void> {
let future: EventLoopFuture<Void>
if self.eventLoop.inEventLoop {
@@ -192,9 +194,11 @@ public final class ChannelPipeline: ChannelInvoker {
/// - name: the name to use for the `ChannelHandler` when it's added. If none is specified a name will be generated.
/// - position: The position in the `ChannelPipeline` to add `handler`. Defaults to `.last`.
/// - returns: the result of adding this handler - either success or failure with an error code if this could not be completed.
fileprivate func addHandlerSync(_ handler: ChannelHandler,
name: String? = nil,
position: ChannelPipeline.Position = .last) -> Result<Void, Error> {
fileprivate func addHandlerSync(
_ handler: ChannelHandler,
name: String? = nil,
position: ChannelPipeline.Position = .last
) -> Result<Void, Error> {
self.eventLoop.assertInEventLoop()
if self.destroyed {
@@ -203,25 +207,33 @@ public final class ChannelPipeline: ChannelInvoker {
switch position {
case .first:
return self.add0(name: name,
handler: handler,
relativeContext: head!,
operation: self.add0(context:after:))
return self.add0(
name: name,
handler: handler,
relativeContext: head!,
operation: self.add0(context:after:)
)
case .last:
return self.add0(name: name,
handler: handler,
relativeContext: tail!,
operation: self.add0(context:before:))
return self.add0(
name: name,
handler: handler,
relativeContext: tail!,
operation: self.add0(context:before:)
)
case .before(let beforeHandler):
return self.add0(name: name,
handler: handler,
relativeHandler: beforeHandler,
operation: self.add0(context:before:))
return self.add0(
name: name,
handler: handler,
relativeHandler: beforeHandler,
operation: self.add0(context:before:)
)
case .after(let afterHandler):
return self.add0(name: name,
handler: handler,
relativeHandler: afterHandler,
operation: self.add0(context:after:))
return self.add0(
name: name,
handler: handler,
relativeHandler: afterHandler,
operation: self.add0(context:after:)
)
}
}
@@ -241,10 +253,12 @@ public final class ChannelPipeline: ChannelInvoker {
/// inserted relative to.
/// - operation: A callback that will insert `handler` relative to `relativeHandler`.
/// - returns: the result of adding this handler - either success or failure with an error code if this could not be completed.
private func add0(name: String?,
handler: ChannelHandler,
relativeHandler: ChannelHandler,
operation: (ChannelHandlerContext, ChannelHandlerContext) -> Void) -> Result<Void, Error> {
private func add0(
name: String?,
handler: ChannelHandler,
relativeHandler: ChannelHandler,
operation: (ChannelHandlerContext, ChannelHandlerContext) -> Void
) -> Result<Void, Error> {
self.eventLoop.assertInEventLoop()
if self.destroyed {
return .failure(ChannelError._ioOnClosedChannel)
@@ -273,10 +287,12 @@ public final class ChannelPipeline: ChannelInvoker {
/// inserted relative to.
/// - operation: A callback that will insert `handler` relative to `relativeHandler`.
/// - returns: the result of adding this handler - either success or failure with an error code if this could not be completed.
private func add0(name: String?,
handler: ChannelHandler,
relativeContext: ChannelHandlerContext,
operation: (ChannelHandlerContext, ChannelHandlerContext) -> Void) -> Result<Void, Error> {
private func add0(
name: String?,
handler: ChannelHandler,
relativeContext: ChannelHandlerContext,
operation: (ChannelHandlerContext, ChannelHandlerContext) -> Void
) -> Result<Void, Error> {
self.eventLoop.assertInEventLoop()
if self.destroyed {
@@ -458,7 +474,7 @@ public final class ChannelPipeline: ChannelInvoker {
/// - handler: the `ChannelHandler` for which the `ChannelHandlerContext` should be returned
/// - returns: the `ChannelHandlerContext` that belongs to the `ChannelHandler`, if one exists.
fileprivate func contextSync(handler: ChannelHandler) -> Result<ChannelHandlerContext, Error> {
return self._contextSync({ $0.handler === handler })
self._contextSync({ $0.handler === handler })
}
/// Returns the `ChannelHandlerContext` that belongs to a `ChannelHandler`.
@@ -487,7 +503,7 @@ public final class ChannelPipeline: ChannelInvoker {
/// - Parameter name: The name of the `ChannelHandler` to find.
/// - Returns: the `ChannelHandlerContext` that belongs to the `ChannelHandler`, if one exists.
fileprivate func contextSync(name: String) -> Result<ChannelHandlerContext, Error> {
return self._contextSync({ $0.name == name })
self._contextSync({ $0.name == name })
}
/// Returns the `ChannelHandlerContext` that belongs to a `ChannelHandler` of the given type.
@@ -527,7 +543,7 @@ public final class ChannelPipeline: ChannelInvoker {
/// Returns if the ``ChannelHandler`` of the given type is contained in the pipeline.
///
/// - Parameters:
/// - name: The name of the handler.
/// - name: The name of the handler.
/// - Returns: An ``EventLoopFuture`` that is succeeded if a handler of the given type is contained in the pipeline. Otherwise
/// the future will be failed with an error.
@inlinable
@@ -541,14 +557,16 @@ public final class ChannelPipeline: ChannelInvoker {
/// - Important: This must be called on the `EventLoop`.
/// - Parameter handlerType: The type of handler to search for.
/// - Returns: the `ChannelHandlerContext` that belongs to the `ChannelHandler`, if one exists.
@inlinable // should be fileprivate
internal func _contextSync<Handler: ChannelHandler>(handlerType: Handler.Type) -> Result<ChannelHandlerContext, Error> {
return self._contextSync({ $0.handler is Handler })
@inlinable // should be fileprivate
internal func _contextSync<Handler: ChannelHandler>(
handlerType: Handler.Type
) -> Result<ChannelHandlerContext, Error> {
self._contextSync({ $0.handler is Handler })
}
/// Synchronously finds a `ChannelHandlerContext` in the `ChannelPipeline`.
/// - Important: This must be called on the `EventLoop`.
@usableFromInline // should be fileprivate
@usableFromInline // should be fileprivate
internal func _contextSync(_ body: (ChannelHandlerContext) -> Bool) -> Result<ChannelHandlerContext, Error> {
self.eventLoop.assertInEventLoop()
@@ -815,11 +833,11 @@ public final class ChannelPipeline: ChannelInvoker {
// These methods are expected to only be called from within the EventLoop
private var firstOutboundCtx: ChannelHandlerContext? {
return self.tail?.prev
self.tail?.prev
}
private var firstInboundCtx: ChannelHandlerContext? {
return self.head?.next
self.head?.next
}
private func close0(mode: CloseMode, promise: EventLoopPromise<Void>?) {
@@ -946,7 +964,7 @@ public final class ChannelPipeline: ChannelInvoker {
}
private var inEventLoop: Bool {
return eventLoop.inEventLoop
eventLoop.inEventLoop
}
/// Create `ChannelPipeline` for a given `Channel`. This method should never be called by the end-user
@@ -958,11 +976,19 @@ public final class ChannelPipeline: ChannelInvoker {
public init(channel: Channel) {
self._channel = channel
self.eventLoop = channel.eventLoop
self.head = nil // we need to initialise these to `nil` so we can use `self` in the lines below
self.tail = nil // we need to initialise these to `nil` so we can use `self` in the lines below
self.head = nil // we need to initialise these to `nil` so we can use `self` in the lines below
self.tail = nil // we need to initialise these to `nil` so we can use `self` in the lines below
self.head = ChannelHandlerContext(name: HeadChannelHandler.name, handler: HeadChannelHandler.sharedInstance, pipeline: self)
self.tail = ChannelHandlerContext(name: TailChannelHandler.name, handler: TailChannelHandler.sharedInstance, pipeline: self)
self.head = ChannelHandlerContext(
name: HeadChannelHandler.name,
handler: HeadChannelHandler.sharedInstance,
pipeline: self
)
self.tail = ChannelHandlerContext(
name: TailChannelHandler.name,
handler: TailChannelHandler.sharedInstance,
pipeline: self
)
self.head?.next = self.tail
self.tail?.prev = self.head
}
@@ -979,8 +1005,10 @@ extension ChannelPipeline {
/// - position: The position in the `ChannelPipeline` to add `handlers`. Defaults to `.last`.
///
/// - returns: A future that will be completed when all of the supplied `ChannelHandler`s were added.
public func addHandlers(_ handlers: [ChannelHandler],
position: ChannelPipeline.Position = .last) -> EventLoopFuture<Void> {
public func addHandlers(
_ handlers: [ChannelHandler],
position: ChannelPipeline.Position = .last
) -> EventLoopFuture<Void> {
let future: EventLoopFuture<Void>
if self.eventLoop.inEventLoop {
@@ -1002,9 +1030,11 @@ extension ChannelPipeline {
/// - position: The position in the `ChannelPipeline` to add `handlers`. Defaults to `.last`.
///
/// - returns: A future that will be completed when all of the supplied `ChannelHandler`s were added.
public func addHandlers(_ handlers: ChannelHandler...,
position: ChannelPipeline.Position = .last) -> EventLoopFuture<Void> {
return self.addHandlers(handlers, position: position)
public func addHandlers(
_ handlers: ChannelHandler...,
position: ChannelPipeline.Position = .last
) -> EventLoopFuture<Void> {
self.addHandlers(handlers, position: position)
}
/// Synchronously adds the provided `ChannelHandler`s to the pipeline in the order given, taking
@@ -1015,8 +1045,10 @@ extension ChannelPipeline {
/// - handlers: The array of `ChannelHandler`s to add.
/// - position: The position in the `ChannelPipeline` to add the handlers.
/// - Returns: A result representing whether the handlers were added or not.
fileprivate func addHandlersSync(_ handlers: [ChannelHandler],
position: ChannelPipeline.Position) -> Result<Void, Error> {
fileprivate func addHandlersSync(
_ handlers: [ChannelHandler],
position: ChannelPipeline.Position
) -> Result<Void, Error> {
switch position {
case .first, .after:
return self._addHandlersSync(handlers.reversed(), position: position)
@@ -1032,8 +1064,10 @@ extension ChannelPipeline {
/// - handlers: A sequence of handlers to add.
/// - position: The position in the `ChannelPipeline` to add the handlers.
/// - Returns: A result representing whether the handlers were added or not.
private func _addHandlersSync<Handlers: Sequence>(_ handlers: Handlers,
position: ChannelPipeline.Position) -> Result<Void, Error> where Handlers.Element == ChannelHandler {
private func _addHandlersSync<Handlers: Sequence>(
_ handlers: Handlers,
position: ChannelPipeline.Position
) -> Result<Void, Error> where Handlers.Element == ChannelHandler {
self.eventLoop.assertInEventLoop()
for handler in handlers {
@@ -1066,7 +1100,7 @@ extension ChannelPipeline {
/// The `EventLoop` of the `Channel` this synchronous operations view corresponds to.
public var eventLoop: EventLoop {
return self._pipeline.eventLoop
self._pipeline.eventLoop
}
/// Add a handler to the pipeline.
@@ -1076,9 +1110,11 @@ extension ChannelPipeline {
/// - handler: The handler to add.
/// - name: The name to use for the `ChannelHandler` when it's added. If no name is specified the one will be generated.
/// - position: The position in the `ChannelPipeline` to add `handler`. Defaults to `.last`.
public func addHandler(_ handler: ChannelHandler,
name: String? = nil,
position: ChannelPipeline.Position = .last) throws {
public func addHandler(
_ handler: ChannelHandler,
name: String? = nil,
position: ChannelPipeline.Position = .last
) throws {
try self._pipeline.addHandlerSync(handler, name: name, position: position).get()
}
@@ -1088,8 +1124,10 @@ extension ChannelPipeline {
/// - Parameters:
/// - handlers: The handlers to add.
/// - position: The position in the `ChannelPipeline` to add `handlers`. Defaults to `.last`.
public func addHandlers(_ handlers: [ChannelHandler],
position: ChannelPipeline.Position = .last) throws {
public func addHandlers(
_ handlers: [ChannelHandler],
position: ChannelPipeline.Position = .last
) throws {
try self._pipeline.addHandlersSync(handlers, position: position).get()
}
@@ -1099,8 +1137,10 @@ extension ChannelPipeline {
/// - Parameters:
/// - handlers: The handlers to add.
/// - position: The position in the `ChannelPipeline` to add `handlers`. Defaults to `.last`.
public func addHandlers(_ handlers: ChannelHandler...,
position: ChannelPipeline.Position = .last) throws {
public func addHandlers(
_ handlers: ChannelHandler...,
position: ChannelPipeline.Position = .last
) throws {
try self._pipeline.addHandlersSync(handlers, position: position).get()
}
@@ -1128,7 +1168,7 @@ extension ChannelPipeline {
/// - Parameter handler: The handler belonging to the context to fetch.
/// - Returns: The `ChannelHandlerContext` associated with the handler.
public func context(handler: ChannelHandler) throws -> ChannelHandlerContext {
return try self._pipeline._contextSync({ $0.handler === handler }).get()
try self._pipeline._contextSync({ $0.handler === handler }).get()
}
/// Returns the `ChannelHandlerContext` for the handler with the given name, if one exists.
@@ -1137,7 +1177,7 @@ extension ChannelPipeline {
/// - Parameter name: The name of the handler whose context is being fetched.
/// - Returns: The `ChannelHandlerContext` associated with the handler.
public func context(name: String) throws -> ChannelHandlerContext {
return try self._pipeline.contextSync(name: name).get()
try self._pipeline.contextSync(name: name).get()
}
/// Returns the `ChannelHandlerContext` for the handler of given type, if one exists.
@@ -1147,7 +1187,7 @@ extension ChannelPipeline {
/// - Returns: The `ChannelHandlerContext` associated with the handler.
@inlinable
public func context<Handler: ChannelHandler>(handlerType: Handler.Type) throws -> ChannelHandlerContext {
return try self._pipeline._contextSync(handlerType: handlerType).get()
try self._pipeline._contextSync(handlerType: handlerType).get()
}
/// Returns the `ChannelHandler` of the given type from the `ChannelPipeline`, if it exists.
@@ -1156,7 +1196,7 @@ extension ChannelPipeline {
/// - Returns: A `ChannelHandler` of the given type if one exists in the `ChannelPipeline`.
@inlinable
public func handler<Handler: ChannelHandler>(type _: Handler.Type) throws -> Handler {
return try self._pipeline._handlerSync(type: Handler.self).get()
try self._pipeline._handlerSync(type: Handler.self).get()
}
/// Fires `channelRegistered` from the head to the tail.
@@ -1307,7 +1347,7 @@ extension ChannelPipeline {
/// Returns a view of operations which can be performed synchronously on this pipeline. All
/// operations **must** be called on the event loop.
public var syncOperations: SynchronousOperations {
return SynchronousOperations(pipeline: self)
SynchronousOperations(pipeline: self)
}
}
@@ -1335,12 +1375,12 @@ extension ChannelPipeline {
extension ChannelPipeline.Position: Sendable {}
/// Special `ChannelHandler` that forwards all events to the `Channel.Unsafe` implementation.
/* private but tests */ final class HeadChannelHandler: _ChannelOutboundHandler {
final class HeadChannelHandler: _ChannelOutboundHandler {
static let name = "head"
static let sharedInstance = HeadChannelHandler()
private init() { }
private init() {}
func register(context: ChannelHandlerContext, promise: EventLoopPromise<Void>?) {
context.channel._channelCore.register0(promise: promise)
@@ -1376,9 +1416,9 @@ extension ChannelPipeline.Position: Sendable {}
}
private extension CloseMode {
extension CloseMode {
/// Returns the error to fail outstanding operations writes with.
var error: any Error {
fileprivate var error: any Error {
switch self {
case .all:
return ChannelError._ioOnClosedChannel
@@ -1391,12 +1431,12 @@ private extension CloseMode {
}
/// Special `ChannelInboundHandler` which will consume all inbound events.
/* private but tests */ final class TailChannelHandler: _ChannelInboundHandler {
final class TailChannelHandler: _ChannelInboundHandler {
static let name = "tail"
static let sharedInstance = TailChannelHandler()
private init() { }
private init() {}
func channelRegistered(context: ChannelHandlerContext) {
// Discard
@@ -1461,11 +1501,11 @@ public final class ChannelHandlerContext: ChannelInvoker {
public let pipeline: ChannelPipeline
public var channel: Channel {
return self.pipeline.channel
self.pipeline.channel
}
public var handler: ChannelHandler {
return self.inboundHandler ?? self.outboundHandler!
self.inboundHandler ?? self.outboundHandler!
}
public var remoteAddress: SocketAddress? {
@@ -1495,7 +1535,7 @@ public final class ChannelHandlerContext: ChannelInvoker {
}
public var eventLoop: EventLoop {
return self.pipeline.eventLoop
self.pipeline.eventLoop
}
public let name: String
@@ -1512,7 +1552,10 @@ public final class ChannelHandlerContext: ChannelInvoker {
self.outboundHandler = handler as? _ChannelOutboundHandler
self.next = nil
self.prev = nil
precondition(self.inboundHandler != nil || self.outboundHandler != nil, "ChannelHandlers need to either be inbound or outbound")
precondition(
self.inboundHandler != nil || self.outboundHandler != nil,
"ChannelHandlers need to either be inbound or outbound"
)
}
/// Send a `channelRegistered` event to the next (inbound) `ChannelHandler` in the `ChannelPipeline`.
@@ -1788,7 +1831,7 @@ public final class ChannelHandlerContext: ChannelInvoker {
}
}
fileprivate func invokeBind(to address: SocketAddress, promise: EventLoopPromise<Void>?) {
fileprivate func invokeBind(to address: SocketAddress, promise: EventLoopPromise<Void>?) {
self.eventLoop.assertInEventLoop()
if let outboundHandler = self.outboundHandler {
@@ -1916,8 +1959,10 @@ extension ChannelHandlerContext {
return
}
self.userTriggeredRemovalStarted = true
(self.handler as! RemovableChannelHandler).removeHandler(context: self,
removalToken: .init(promise: promise))
(self.handler as! RemovableChannelHandler).removeHandler(
context: self,
removalToken: .init(promise: promise)
)
}
}
@@ -1933,15 +1978,17 @@ extension ChannelPipeline: CustomDebugStringConvertible {
//
var desc = ["ChannelPipeline[\(ObjectIdentifier(self))]:"]
let debugInfos = self.collectHandlerDebugInfos()
let maxIncomingTypeNameCount = debugInfos.filter { $0.isIncoming }
let maxIncomingTypeNameCount =
debugInfos.filter { $0.isIncoming }
.map { $0.typeName.count }
.max() ?? 0
let maxOutgoingTypeNameCount = debugInfos.filter { $0.isOutgoing }
let maxOutgoingTypeNameCount =
debugInfos.filter { $0.isOutgoing }
.map { $0.typeName.count }
.max() ?? 0
func whitespace(count: Int) -> String {
return String(repeating: " ", count: count)
String(repeating: " ", count: count)
}
if debugInfos.isEmpty {
@@ -1979,9 +2026,11 @@ extension ChannelPipeline: CustomDebugStringConvertible {
/// - type: the type of `ChannelHandler` to return.
@inlinable
public func handler<Handler: ChannelHandler>(type _: Handler.Type) -> EventLoopFuture<Handler> {
return self.context(handlerType: Handler.self).map { context in
self.context(handlerType: Handler.self).map { context in
guard let typedContext = context.handler as? Handler else {
preconditionFailure("Expected channel handler of type \(Handler.self), got \(type(of: context.handler)) instead.")
preconditionFailure(
"Expected channel handler of type \(Handler.self), got \(type(of: context.handler)) instead."
)
}
return typedContext
@@ -1993,11 +2042,13 @@ extension ChannelPipeline: CustomDebugStringConvertible {
/// - Important: This must be called on the `EventLoop`.
/// - Parameters:
/// - type: the type of `ChannelHandler` to return.
@inlinable // should be fileprivate
@inlinable // should be fileprivate
internal func _handlerSync<Handler: ChannelHandler>(type _: Handler.Type) -> Result<Handler, Error> {
return self._contextSync(handlerType: Handler.self).map { context in
self._contextSync(handlerType: Handler.self).map { context in
guard let typedContext = context.handler as? Handler else {
preconditionFailure("Expected channel handler of type \(Handler.self), got \(type(of: context.handler)) instead.")
preconditionFailure(
"Expected channel handler of type \(Handler.self), got \(type(of: context.handler)) instead."
)
}
return typedContext
}
@@ -2007,13 +2058,13 @@ extension ChannelPipeline: CustomDebugStringConvertible {
let handler: ChannelHandler
let name: String
var isIncoming: Bool {
return self.handler is _ChannelInboundHandler
self.handler is _ChannelInboundHandler
}
var isOutgoing: Bool {
return self.handler is _ChannelOutboundHandler
self.handler is _ChannelOutboundHandler
}
var typeName: String {
return "\(type(of: self.handler))"
"\(type(of: self.handler))"
}
}
+80 -61
View File
@@ -27,7 +27,7 @@ public struct CircularBuffer<Element>: CustomStringConvertible {
@inlinable
internal var mask: Int {
return self._buffer.count &- 1
self._buffer.count &- 1
}
@inlinable
@@ -42,17 +42,17 @@ public struct CircularBuffer<Element>: CustomStringConvertible {
@inlinable
internal func indexBeforeHeadIdx() -> Int {
return self.indexAdvanced(index: self.headBackingIndex, by: -1)
self.indexAdvanced(index: self.headBackingIndex, by: -1)
}
@inlinable
internal func indexBeforeTailIdx() -> Int {
return self.indexAdvanced(index: self.tailBackingIndex, by: -1)
self.indexAdvanced(index: self.tailBackingIndex, by: -1)
}
@inlinable
internal func indexAdvanced(index: Int, by: Int) -> Int {
return (index &+ by) & self.mask
(index &+ by) & self.mask
}
/// An opaque `CircularBuffer` index.
@@ -69,7 +69,7 @@ public struct CircularBuffer<Element>: CustomStringConvertible {
@inlinable
internal var backingIndex: Int {
return Int(self._backingIndex)
Int(self._backingIndex)
}
@inlinable
@@ -85,9 +85,8 @@ public struct CircularBuffer<Element>: CustomStringConvertible {
@inlinable
public static func == (lhs: Index, rhs: Index) -> Bool {
return lhs._backingIndex == rhs._backingIndex &&
lhs._backingCheck == rhs._backingCheck &&
lhs.isIndexGEQHeadIndex == rhs.isIndexGEQHeadIndex
lhs._backingIndex == rhs._backingIndex && lhs._backingCheck == rhs._backingCheck
&& lhs.isIndexGEQHeadIndex == rhs.isIndexGEQHeadIndex
}
@inlinable
@@ -105,8 +104,8 @@ public struct CircularBuffer<Element>: CustomStringConvertible {
@usableFromInline
internal func isValidIndex(for ring: CircularBuffer<Element>) -> Bool {
return self._backingCheck == _UInt24.max || Int(self._backingCheck) == ring.count
}
self._backingCheck == _UInt24.max || Int(self._backingCheck) == ring.count
}
}
}
@@ -128,13 +127,13 @@ extension CircularBuffer: Collection, MutableCollection {
/// - Returns: The index value immediately after `i`.
@inlinable
public func index(after: Index) -> Index {
return self.index(after, offsetBy: 1)
self.index(after, offsetBy: 1)
}
/// Returns the index before `index`.
@inlinable
public func index(before: Index) -> Index {
return self.index(before, offsetBy: -1)
self.index(before, offsetBy: -1)
}
/// Accesses the element at the specified index.
@@ -152,15 +151,19 @@ extension CircularBuffer: Collection, MutableCollection {
@inlinable
public subscript(position: Index) -> Element {
get {
assert(position.isValidIndex(for: self),
"illegal index used, index was for CircularBuffer with count \(position._backingCheck), " +
"but actual count is \(self.count)")
assert(
position.isValidIndex(for: self),
"illegal index used, index was for CircularBuffer with count \(position._backingCheck), "
+ "but actual count is \(self.count)"
)
return self._buffer[position.backingIndex]!
}
set {
assert(position.isValidIndex(for: self),
"illegal index used, index was for CircularBuffer with count \(position._backingCheck), " +
"but actual count is \(self.count)")
assert(
position.isValidIndex(for: self),
"illegal index used, index was for CircularBuffer with count \(position._backingCheck), "
+ "but actual count is \(self.count)"
)
self._buffer[position.backingIndex] = newValue
}
}
@@ -170,9 +173,11 @@ extension CircularBuffer: Collection, MutableCollection {
/// If the `CircularBuffer` is empty, `startIndex` is equal to `endIndex`.
@inlinable
public var startIndex: Index {
return .init(backingIndex: self.headBackingIndex,
backingCount: self.count,
backingIndexOfHead: self.headBackingIndex)
.init(
backingIndex: self.headBackingIndex,
backingCount: self.count,
backingIndexOfHead: self.headBackingIndex
)
}
/// The `CircularBuffer`'s "past the end" position---that is, the position one
@@ -186,9 +191,11 @@ extension CircularBuffer: Collection, MutableCollection {
/// If the `CircularBuffer` is empty, `endIndex` is equal to `startIndex`.
@inlinable
public var endIndex: Index {
return .init(backingIndex: self.tailBackingIndex,
backingCount: self.count,
backingIndexOfHead: self.headBackingIndex)
.init(
backingIndex: self.tailBackingIndex,
backingCount: self.count,
backingIndexOfHead: self.headBackingIndex
)
}
/// Returns the distance between two indices.
@@ -251,14 +258,14 @@ extension CircularBuffer: Collection, MutableCollection {
return (self[self.endIndex..<self.endIndex].makeIterator(), self.count)
}
// These are implemented as no-ops for performance reasons.
@inlinable
public func _failEarlyRangeCheck(_ index: Index, bounds: Range<Index>) {}
@inlinable
public func _failEarlyRangeCheck(_ index: Index, bounds: ClosedRange<Index>) {}
@inlinable
public func _failEarlyRangeCheck(_ range: Range<Index>, bounds: Range<Index>) {}
}
@@ -294,9 +301,11 @@ extension CircularBuffer: RandomAccessCollection {
/// value of `distance`.
@inlinable
public func index(_ i: Index, offsetBy distance: Int) -> Index {
return .init(backingIndex: (i.backingIndex &+ distance) & self.mask,
backingCount: self.count,
backingIndexOfHead: self.headBackingIndex)
.init(
backingIndex: (i.backingIndex &+ distance) & self.mask,
backingCount: self.count,
backingIndexOfHead: self.headBackingIndex
)
}
@inlinable
@@ -345,7 +354,7 @@ extension CircularBuffer {
public mutating func append(_ value: Element) {
self._buffer[self.tailBackingIndex] = value
self.advanceTailIdx(by: 1)
if self.headBackingIndex == self.tailBackingIndex {
// No more room left for another append so grow the buffer now.
self._doubleCapacity()
@@ -424,24 +433,24 @@ extension CircularBuffer {
self._buffer = newBacking
assert(self.verifyInvariants())
}
/// Return element `offset` from first element.
///
/// *O(1)*
@inlinable
public subscript(offset offset: Int) -> Element {
get {
return self[self.index(self.startIndex, offsetBy: offset)]
self[self.index(self.startIndex, offsetBy: offset)]
}
set {
self[self.index(self.startIndex, offsetBy: offset)] = newValue
}
}
/// Returns whether the ring is empty.
@inlinable
public var isEmpty: Bool {
return self.headBackingIndex == self.tailBackingIndex
self.headBackingIndex == self.tailBackingIndex
}
/// Returns the number of element in the ring.
@@ -457,7 +466,7 @@ extension CircularBuffer {
/// The total number of elements that the ring can contain without allocating new storage.
@inlinable
public var capacity: Int {
return self._buffer.count
self._buffer.count
}
/// Removes all members from the circular buffer whist keeping the capacity.
@@ -474,7 +483,6 @@ extension CircularBuffer {
assert(self.verifyInvariants())
}
/// Modify the element at `index`.
///
/// This function exists to provide a method of modifying the element in its underlying backing storage, instead
@@ -491,10 +499,13 @@ extension CircularBuffer {
/// - index: The index of the object that should be modified. If this index is invalid this function will trap.
/// - modifyFunc: The function to apply to the modified object.
@inlinable
public mutating func modify<Result>(_ index: Index, _ modifyFunc: (inout Element) throws -> Result) rethrows -> Result {
return try modifyFunc(&self._buffer[index.backingIndex]!)
public mutating func modify<Result>(
_ index: Index,
_ modifyFunc: (inout Element) throws -> Result
) rethrows -> Result {
try modifyFunc(&self._buffer[index.backingIndex]!)
}
// MARK: CustomStringConvertible implementation
/// Returns a human readable description of the ring.
public var description: String {
@@ -572,14 +583,13 @@ extension CircularBuffer: RangeReplaceableCollection {
public mutating func removeLast(_ k: Int) {
precondition(k <= self.count, "Number of elements to drop bigger than the amount of elements in the buffer.")
var idx = self.tailBackingIndex
for _ in 0 ..< k {
for _ in 0..<k {
idx = self.indexAdvanced(index: idx, by: -1)
self._buffer[idx] = nil
}
self.tailBackingIndex = idx
}
/// Removes the specified number of elements from the beginning of the
/// `CircularBuffer`.
///
@@ -595,7 +605,7 @@ extension CircularBuffer: RangeReplaceableCollection {
public mutating func removeFirst(_ k: Int) {
precondition(k <= self.count, "Number of elements to drop bigger than the amount of elements in the buffer.")
var idx = self.headBackingIndex
for _ in 0 ..< k {
for _ in 0..<k {
self._buffer[idx] = nil
idx = self.indexAdvanced(index: idx, by: 1)
}
@@ -620,7 +630,7 @@ extension CircularBuffer: RangeReplaceableCollection {
}
return self.first!
}
/// Removes and returns the last element of the `CircularBuffer`.
///
/// The `CircularBuffer` must not be empty.
@@ -652,15 +662,22 @@ extension CircularBuffer: RangeReplaceableCollection {
///
/// *O(m)* where _m_ is the combined length of the collection and _newElements_
@inlinable
public mutating func replaceSubrange<C: Collection>(_ subrange: Range<Index>, with newElements: C) where Element == C.Element {
precondition(subrange.lowerBound >= self.startIndex && subrange.upperBound <= self.endIndex,
"Subrange out of bounds")
assert(subrange.lowerBound.isValidIndex(for: self),
"illegal index used, index was for CircularBuffer with count \(subrange.lowerBound._backingCheck), " +
"but actual count is \(self.count)")
assert(subrange.upperBound.isValidIndex(for: self),
"illegal index used, index was for CircularBuffer with count \(subrange.upperBound._backingCheck), " +
"but actual count is \(self.count)")
public mutating func replaceSubrange<C: Collection>(_ subrange: Range<Index>, with newElements: C)
where Element == C.Element {
precondition(
subrange.lowerBound >= self.startIndex && subrange.upperBound <= self.endIndex,
"Subrange out of bounds"
)
assert(
subrange.lowerBound.isValidIndex(for: self),
"illegal index used, index was for CircularBuffer with count \(subrange.lowerBound._backingCheck), "
+ "but actual count is \(self.count)"
)
assert(
subrange.upperBound.isValidIndex(for: self),
"illegal index used, index was for CircularBuffer with count \(subrange.upperBound._backingCheck), "
+ "but actual count is \(self.count)"
)
let subrangeCount = self.distance(from: subrange.lowerBound, to: subrange.upperBound)
@@ -674,14 +691,14 @@ extension CircularBuffer: RangeReplaceableCollection {
self.removeSubrange(subrange)
} else {
var newBuffer: ContiguousArray<Element?> = []
let neededNewCapacity = self.count + newElements.count - subrangeCount + 1 /* always one spare */
let neededNewCapacity = self.count + newElements.count - subrangeCount + 1 // always one spare
let newCapacity = Swift.max(self.capacity, neededNewCapacity.nextPowerOf2())
newBuffer.reserveCapacity(newCapacity)
// This mapping is required due to an inconsistent ability to append sequences of non-optional
// to optional sequences.
// https://bugs.swift.org/browse/SR-7921
newBuffer.append(contentsOf: self[self.startIndex ..< subrange.lowerBound].lazy.map { $0 })
newBuffer.append(contentsOf: self[self.startIndex..<subrange.lowerBound].lazy.map { $0 })
newBuffer.append(contentsOf: newElements.lazy.map { $0 })
newBuffer.append(contentsOf: self[subrange.upperBound..<self.endIndex].lazy.map { $0 })
@@ -725,9 +742,11 @@ extension CircularBuffer: RangeReplaceableCollection {
@discardableResult
@inlinable
public mutating func remove(at position: Index) -> Element {
assert(position.isValidIndex(for: self),
"illegal index used, index was for CircularBuffer with count \(position._backingCheck), " +
"but actual count is \(self.count)")
assert(
position.isValidIndex(for: self),
"illegal index used, index was for CircularBuffer with count \(position._backingCheck), "
+ "but actual count is \(self.count)"
)
defer {
assert(self.verifyInvariants())
}
@@ -807,13 +826,13 @@ extension CircularBuffer {
}
internal func testOnly_verifyInvariantsForNonSlices() -> Bool {
return self.verifyInvariants() && self.unreachableAreNil()
self.verifyInvariants() && self.unreachableAreNil()
}
}
extension CircularBuffer: Equatable where Element: Equatable {
public static func ==(lhs: CircularBuffer, rhs: CircularBuffer) -> Bool {
return lhs.count == rhs.count && zip(lhs, rhs).allSatisfy(==)
public static func == (lhs: CircularBuffer, rhs: CircularBuffer) -> Bool {
lhs.count == rhs.count && zip(lhs, rhs).allSatisfy(==)
}
}
+57 -36
View File
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
/// State of the current decoding process.
public enum DecodingState: Sendable {
/// Continue decoding.
@@ -43,7 +42,6 @@ extension ByteToMessageDecoderError {
}
}
/// `ByteToMessageDecoder`s decode bytes in a stream-like fashion from `ByteBuffer` to another message type.
///
/// ### Purpose
@@ -63,7 +61,7 @@ extension ByteToMessageDecoderError {
/// ### Implementing ByteToMessageDecoder
///
/// A type that implements `ByteToMessageDecoder` may implement two methods: decode and decodeLast. Implementations
/// must implement decode: if they do not implement decodeLast, a default implementation will be used that
/// must implement decode: if they do not implement decodeLast, a default implementation will be used that
/// simply calls decode.
///
/// `decode` is the main decoding method, and is the one that will be called most often. `decode` is invoked
@@ -176,7 +174,11 @@ public protocol ByteToMessageDecoder {
/// - seenEOF: `true` if EOF has been seen. Usually if this is `false` the handler has been removed.
/// - returns: `DecodingState.continue` if we should continue calling this method or `DecodingState.needMoreData` if it should be called
/// again when more data is present in the `ByteBuffer`.
mutating func decodeLast(context: ChannelHandlerContext, buffer: inout ByteBuffer, seenEOF: Bool) throws -> DecodingState
mutating func decodeLast(
context: ChannelHandlerContext,
buffer: inout ByteBuffer,
seenEOF: Bool
) throws -> DecodingState
/// Called once this `ByteToMessageDecoder` is removed from the `ChannelPipeline`.
///
@@ -237,15 +239,19 @@ extension ByteToMessageDecoder {
@inlinable
public func wrapInboundOut(_ value: InboundOut) -> NIOAny {
return NIOAny(value)
NIOAny(value)
}
@inlinable
public static func wrapInboundOut(_ value: InboundOut) -> NIOAny {
return NIOAny(value)
NIOAny(value)
}
public mutating func decodeLast(context: ChannelHandlerContext, buffer: inout ByteBuffer, seenEOF: Bool) throws -> DecodingState {
public mutating func decodeLast(
context: ChannelHandlerContext,
buffer: inout ByteBuffer,
seenEOF: Bool
) throws -> DecodingState {
while try self.decode(context: context, buffer: &buffer) == .continue {}
return .needMoreData
}
@@ -297,7 +303,7 @@ extension B2MDBuffer {
case .ready where self.buffers.count > 0:
var buffer = self.buffers.removeFirst()
buffer.writeBuffers(self.buffers)
self.buffers.removeAll(keepingCapacity: self.buffers.capacity < 16) // don't grow too much
self.buffers.removeAll(keepingCapacity: self.buffers.capacity < 16) // don't grow too much
if buffer.readableBytes > 0 || allowEmptyBuffer {
self.state = .processingInProgress
return .available(buffer)
@@ -314,7 +320,7 @@ extension B2MDBuffer {
}
}
mutating func finishProcessing(remainder buffer: inout ByteBuffer) -> Void {
mutating func finishProcessing(remainder buffer: inout ByteBuffer) {
assert(self.state == .processingInProgress)
self.state = .ready
if buffer.readableBytes == 0 && self.buffers.isEmpty {
@@ -326,7 +332,8 @@ extension B2MDBuffer {
} else {
buffer.discardReadBytes()
buffer.writeBuffers(self.buffers)
self.buffers.removeAll(keepingCapacity: self.buffers.capacity < 16) // don't grow too much
// don't grow too much
self.buffers.removeAll(keepingCapacity: self.buffers.capacity < 16)
self.buffers.append(buffer)
}
}
@@ -339,8 +346,8 @@ extension B2MDBuffer {
}
// MARK: B2MDBuffer Helpers
private extension ByteBuffer {
mutating func writeBuffers(_ buffers: CircularBuffer<ByteBuffer>) {
extension ByteBuffer {
fileprivate mutating func writeBuffers(_ buffers: CircularBuffer<ByteBuffer>) {
guard buffers.count > 0 else {
return
}
@@ -355,8 +362,8 @@ private extension ByteBuffer {
}
}
private extension B2MDBuffer {
func _testOnlyOneBuffer() -> ByteBuffer? {
extension B2MDBuffer {
fileprivate func _testOnlyOneBuffer() -> ByteBuffer? {
switch self.buffers.count {
case 0:
return nil
@@ -452,12 +459,15 @@ public final class ByteToMessageHandler<Decoder: ByteToMessageDecoder> {
}
}
internal private(set) var decoder: Decoder? // only `nil` if we're already decoding (ie. we're re-entered)
// only `nil` if we're already decoding (ie. we're re-entered)
internal private(set) var decoder: Decoder?
private let maximumBufferSize: Int?
private var queuedWrites = CircularBuffer<NIOAny>(initialCapacity: 1) // queues writes received whilst we're already decoding (re-entrant write)
// queues writes received whilst we're already decoding (re-entrant write)
private var queuedWrites = CircularBuffer<NIOAny>(initialCapacity: 1)
private var state: State = .active {
willSet {
assert(!self.state.isFinalState, "illegal state on state set: \(self.state)") // we can never leave final states
// we can never leave final states
assert(!self.state.isFinalState, "illegal state on state set: \(self.state)")
}
}
private var removalState: RemovalState = .notAddedToPipeline
@@ -484,8 +494,10 @@ public final class ByteToMessageHandler<Decoder: ByteToMessageDecoder> {
deinit {
if self.removalState != .notAddedToPipeline {
// we have been added to the pipeline, if not, we don't need to check our state.
assert(self.removalState == .handlerRemovedCalled,
"illegal state in deinit: removalState = \(self.removalState)")
assert(
self.removalState == .handlerRemovedCalled,
"illegal state in deinit: removalState = \(self.removalState)"
)
assert(self.state.isFinalState, "illegal state in deinit: state = \(self.state)")
}
}
@@ -497,7 +509,7 @@ extension ByteToMessageHandler: Sendable {}
// MARK: ByteToMessageHandler: Test Helpers
extension ByteToMessageHandler {
internal var cumulationBuffer: ByteBuffer? {
return self.buffer._testOnlyOneBuffer()
self.buffer._testOnlyOneBuffer()
}
}
@@ -514,11 +526,13 @@ extension ByteToMessageHandler: CanDequeueWrites where Decoder: WriteObservingBy
}
}
// MARK: ByteToMessageHandler's Main API
extension ByteToMessageHandler {
@inline(__always) // allocations otherwise (reconsider with Swift 5.1)
private func withNextBuffer(allowEmptyBuffer: Bool, _ body: (inout Decoder, inout ByteBuffer) throws -> DecodingState) rethrows -> B2MDBuffer.BufferProcessingResult {
@inline(__always) // allocations otherwise (reconsider with Swift 5.1)
private func withNextBuffer(
allowEmptyBuffer: Bool,
_ body: (inout Decoder, inout ByteBuffer) throws -> DecodingState
) rethrows -> B2MDBuffer.BufferProcessingResult {
switch self.buffer.startProcessing(allowEmptyBuffer: allowEmptyBuffer) {
case .bufferAlreadyBeingProcessed:
return .cannotProcessReentrantly
@@ -528,7 +542,8 @@ extension ByteToMessageHandler {
var possiblyReclaimBytes = false
var decoder: Decoder? = nil
swap(&decoder, &self.decoder)
assert(decoder != nil) // self.decoder only `nil` if we're being re-entered, but .available means we're not
// self.decoder only `nil` if we're being re-entered, but .available means we're not
assert(decoder != nil)
defer {
swap(&decoder, &self.decoder)
if buffer.readableBytes > 0 && possiblyReclaimBytes {
@@ -575,7 +590,10 @@ extension ByteToMessageHandler {
}
}
private func decodeLoop(context: ChannelHandlerContext, decodeMode: DecodeMode) throws -> B2MDBuffer.BufferProcessingResult {
private func decodeLoop(
context: ChannelHandlerContext,
decodeMode: DecodeMode
) throws -> B2MDBuffer.BufferProcessingResult {
assert(!self.state.isError)
var allowEmptyBuffer = decodeMode == .last
while (self.state.isActive && self.removalState == .notBeingRemoved) || decodeMode == .last {
@@ -588,7 +606,9 @@ extension ByteToMessageHandler {
allowEmptyBuffer = false
decoderResult = try decoder.decodeLast(context: context, buffer: &buffer, seenEOF: self.seenEOF)
}
if decoderResult == .needMoreData, let maximumBufferSize = self.maximumBufferSize, buffer.readableBytes > maximumBufferSize {
if decoderResult == .needMoreData, let maximumBufferSize = self.maximumBufferSize,
buffer.readableBytes > maximumBufferSize
{
throw ByteToMessageDecoderError.PayloadTooLargeError()
}
return decoderResult
@@ -600,7 +620,7 @@ extension ByteToMessageHandler {
case .didProcess(.needMoreData):
if self.queuedWrites.count > 0 {
self.tryDecodeWrites()
continue // we might have received more, so let's spin once more
continue // we might have received more, so let's spin once more
} else {
return .didProcess(.needMoreData)
}
@@ -612,7 +632,6 @@ extension ByteToMessageHandler {
}
}
// MARK: ByteToMessageHandler: ChannelInboundHandler
extension ByteToMessageHandler: ChannelInboundHandler {
@@ -623,11 +642,10 @@ extension ByteToMessageHandler: ChannelInboundHandler {
self.removalState = .notBeingRemoved
self.buffer = B2MDBuffer(emptyByteBuffer: context.channel.allocator.buffer(capacity: 0))
// here we can force it because we know that the decoder isn't in use if we're just adding this handler
self.selfAsCanDequeueWrites = self as? CanDequeueWrites // we need to cache this as it allocates.
self.selfAsCanDequeueWrites = self as? CanDequeueWrites // we need to cache this as it allocates.
self.decoder!.decoderAdded(context: context)
}
public func handlerRemoved(context: ChannelHandlerContext) {
// very likely, the removal state is `.notBeingRemoved` or `.removalCompleted` here but we can't assert it
// because the pipeline might be torn down during the formal removal process.
@@ -656,14 +674,14 @@ extension ByteToMessageHandler: ChannelInboundHandler {
case .didProcess:
switch self.state {
case .active:
() // cool, all normal
() // cool, all normal
case .done, .error:
() // fair, all done already
() // fair, all done already
case .leftoversNeedProcessing:
// seems like we received a `channelInactive` or `handlerRemoved` whilst we were processing a read
switch try self.decodeLoop(context: context, decodeMode: .last) {
case .didProcess:
() // expected and cool
() // expected and cool
case .cannotProcessReentrantly:
preconditionFailure("bug in NIO: non-reentrant decode loop couldn't run \(self), \(self.state)")
}
@@ -698,7 +716,8 @@ extension ByteToMessageHandler: ChannelInboundHandler {
}
}
extension ByteToMessageHandler: ChannelOutboundHandler, _ChannelOutboundHandler where Decoder: WriteObservingByteToMessageDecoder {
extension ByteToMessageHandler: ChannelOutboundHandler, _ChannelOutboundHandler
where Decoder: WriteObservingByteToMessageDecoder {
public typealias OutboundIn = Decoder.OutboundIn
public func write(context: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) {
if self.decoder != nil {
@@ -785,8 +804,10 @@ extension MessageToByteHandler: Sendable {}
extension MessageToByteHandler {
public func handlerAdded(context: ChannelHandlerContext) {
precondition(self.state.readyToBeAddedToChannel,
"illegal state when adding to Channel: \(self.state)")
precondition(
self.state.readyToBeAddedToChannel,
"illegal state when adding to Channel: \(self.state)"
)
self.state = .operational
self.buffer = context.channel.allocator.buffer(capacity: 256)
}
+16 -14
View File
@@ -20,7 +20,7 @@ extension NIOClientTCPBootstrapProtocol {
/// - returns: The updated bootstrap with and options applied.
public func _applyChannelConvenienceOptions(_ options: inout ChannelOptions.TCPConvenienceOptions) -> Self {
// Default is to consume no options and not update self.
return self
self
}
}
@@ -34,8 +34,10 @@ extension NIOClientTCPBootstrap {
var optionsRemaining = options
// First give the underlying a chance to consume options.
let withUnderlyingOverrides =
NIOClientTCPBootstrap(self,
updating: underlyingBootstrap._applyChannelConvenienceOptions(&optionsRemaining))
NIOClientTCPBootstrap(
self,
updating: underlyingBootstrap._applyChannelConvenienceOptions(&optionsRemaining)
)
// Default apply any remaining options.
return optionsRemaining.applyFallbackMapping(withUnderlyingOverrides)
}
@@ -84,11 +86,11 @@ extension ChannelOptions {
/// A TCP channel option which can be applied to a bootstrap using convenience notation.
public struct TCPConvenienceOption: Hashable, Sendable {
fileprivate var data: ConvenienceOption
private init(_ data: ConvenienceOption) {
self.data = data
}
fileprivate enum ConvenienceOption: Hashable {
case allowLocalEndpointReuse
case disableAutoRead
@@ -101,17 +103,17 @@ extension ChannelOptions {
extension ChannelOptions.TCPConvenienceOption {
/// Allow immediately reusing a local address.
public static let allowLocalEndpointReuse = ChannelOptions.TCPConvenienceOption(.allowLocalEndpointReuse)
/// The user will manually call `Channel.read` once all the data is read from the transport.
public static let disableAutoRead = ChannelOptions.TCPConvenienceOption(.disableAutoRead)
/// Allows users to configure whether the `Channel` will close itself when its remote
/// peer shuts down its send stream, or whether it will remain open. If set to `false` (the default), the `Channel`
/// will be closed automatically if the remote peer shuts down its send stream. If set to true, the `Channel` will
/// not be closed: instead, a `ChannelEvent.inboundClosed` user event will be sent on the `ChannelPipeline`,
/// and no more data will be received.
public static let allowRemoteHalfClosure =
ChannelOptions.TCPConvenienceOption(.allowRemoteHalfClosure)
ChannelOptions.TCPConvenienceOption(.allowRemoteHalfClosure)
}
extension ChannelOptions {
@@ -120,7 +122,7 @@ extension ChannelOptions {
var allowLocalEndpointReuse = false
var disableAutoRead = false
var allowRemoteHalfClosure = false
/// Construct from an array literal.
@inlinable
public init(arrayLiteral elements: TCPConvenienceOption...) {
@@ -128,7 +130,7 @@ extension ChannelOptions {
self.add(element)
}
}
@usableFromInline
mutating func add(_ element: TCPConvenienceOption) {
switch element.data {
@@ -140,7 +142,7 @@ extension ChannelOptions {
self.disableAutoRead = true
}
}
/// Caller is consuming the knowledge that `allowLocalEndpointReuse` was set or not.
/// The setting will nolonger be set after this call.
/// - Returns: If `allowLocalEndpointReuse` was set.
@@ -150,7 +152,7 @@ extension ChannelOptions {
}
return Types.ConvenienceOptionValue<Void>(flag: self.allowLocalEndpointReuse)
}
/// Caller is consuming the knowledge that disableAutoRead was set or not.
/// The setting will nolonger be set after this call.
/// - Returns: If disableAutoRead was set.
@@ -160,7 +162,7 @@ extension ChannelOptions {
}
return Types.ConvenienceOptionValue<Void>(flag: self.disableAutoRead)
}
/// Caller is consuming the knowledge that allowRemoteHalfClosure was set or not.
/// The setting will nolonger be set after this call.
/// - Returns: If allowRemoteHalfClosure was set.
@@ -170,7 +172,7 @@ extension ChannelOptions {
}
return Types.ConvenienceOptionValue<Void>(flag: self.allowRemoteHalfClosure)
}
mutating func applyFallbackMapping(_ universalBootstrap: NIOClientTCPBootstrap) -> NIOClientTCPBootstrap {
var result = universalBootstrap
if self.consumeAllowLocalEndpointReuse().isSet {
+6 -6
View File
@@ -80,7 +80,7 @@ internal final class DeadChannel: Channel, @unchecked Sendable {
let pipeline: ChannelPipeline
public var closeFuture: EventLoopFuture<Void> {
return self.eventLoop.makeSucceededFuture(())
self.eventLoop.makeSucceededFuture(())
}
internal init(pipeline: ChannelPipeline) {
@@ -90,25 +90,25 @@ internal final class DeadChannel: Channel, @unchecked Sendable {
// This is `Channel` API so must be thread-safe.
var allocator: ByteBufferAllocator {
return ByteBufferAllocator()
ByteBufferAllocator()
}
var localAddress: SocketAddress? {
return nil
nil
}
var remoteAddress: SocketAddress? {
return nil
nil
}
let parent: Channel? = nil
func setOption<Option: ChannelOption>(_ option: Option, value: Option.Value) -> EventLoopFuture<Void> {
return self.pipeline.eventLoop.makeFailedFuture(ChannelError._ioOnClosedChannel)
self.pipeline.eventLoop.makeFailedFuture(ChannelError._ioOnClosedChannel)
}
func getOption<Option: ChannelOption>(_ option: Option) -> EventLoopFuture<Option.Value> {
return eventLoop.makeFailedFuture(ChannelError._ioOnClosedChannel)
eventLoop.makeFailedFuture(ChannelError._ioOnClosedChannel)
}
let isWritable = false
+12 -4
View File
@@ -15,13 +15,21 @@
extension EventLoop {
@inlinable
@available(*, deprecated, message: "Please don't pass file:line:, there's no point.")
public func makeFailedFuture<T>(_ error: Error, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<T> {
return self.makeFailedFuture(error)
public func makeFailedFuture<T>(
_ error: Error,
file: StaticString = #fileID,
line: UInt = #line
) -> EventLoopFuture<T> {
self.makeFailedFuture(error)
}
@inlinable
@available(*, deprecated, message: "Please don't pass file:line:, there's no point.")
public func makeSucceededFuture<Success>(_ value: Success, file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Success> {
return self.makeSucceededFuture(value)
public func makeSucceededFuture<Success>(
_ value: Success,
file: StaticString = #fileID,
line: UInt = #line
) -> EventLoopFuture<Success> {
self.makeSucceededFuture(value)
}
}
@@ -19,7 +19,7 @@
/// Implementers of `EventLoop` should consider conforming to this protocol as
/// well on Swift 5.9 and later.
@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
public protocol NIOSerialEventLoopExecutor: EventLoop, SerialExecutor { }
public protocol NIOSerialEventLoopExecutor: EventLoop, SerialExecutor {}
@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
extension NIOSerialEventLoopExecutor {
+80 -60
View File
@@ -12,11 +12,12 @@
//
//===----------------------------------------------------------------------===//
import NIOConcurrencyHelpers
import Dispatch
import NIOConcurrencyHelpers
#if os(Linux)
import CNIOLinux
#endif // os(Linux)
#endif // os(Linux)
/// Returned once a task was scheduled on the `EventLoop` for later execution.
///
@@ -24,8 +25,8 @@ import CNIOLinux
/// will be notified once the execution is complete.
public struct Scheduled<T> {
@usableFromInline typealias CancelationCallback = @Sendable () -> Void
/* private but usableFromInline */ @usableFromInline let _promise: EventLoopPromise<T>
/* private but usableFromInline */ @usableFromInline let _cancellationTask: CancelationCallback
@usableFromInline let _promise: EventLoopPromise<T>
@usableFromInline let _cancellationTask: CancelationCallback
@inlinable
@preconcurrency
@@ -47,7 +48,7 @@ public struct Scheduled<T> {
/// Returns the `EventLoopFuture` which will be notified once the execution of the scheduled task completes.
@inlinable
public var futureResult: EventLoopFuture<T> {
return self._promise.futureResult
self._promise.futureResult
}
}
@@ -202,7 +203,7 @@ public struct EventLoopIterator: Sequence, IteratorProtocol {
///
/// - returns: The next `EventLoop` if a next element exists; otherwise, `nil`.
public mutating func next() -> EventLoop? {
return self.eventLoops.next()
self.eventLoops.next()
}
}
@@ -247,7 +248,7 @@ public protocol EventLoop: EventLoopGroup {
///
/// If it is necessary for correctness to confirm that you're on an event loop, prefer ``preconditionInEventLoop(file:line:)-7ukrq``.
var inEventLoop: Bool { get }
/// Submit a given task to be executed by the `EventLoop`
@preconcurrency
func execute(_ task: @escaping @Sendable () -> Void)
@@ -361,7 +362,7 @@ public protocol EventLoop: EventLoopGroup {
extension EventLoop {
/// Default implementation of `makeSucceededVoidFuture`: Return a fresh future (which will allocate).
public func makeSucceededVoidFuture() -> EventLoopFuture<Void> {
return EventLoopFuture(eventLoop: self, value: ())
EventLoopFuture(eventLoop: self, value: ())
}
public func _preconditionSafeToWait(file: StaticString, line: UInt) {
@@ -374,8 +375,9 @@ extension EventLoop {
}
/// Default implementation of `_promiseCompleted`: does nothing.
public func _promiseCompleted(futureIdentifier: _NIOEventLoopFutureIdentifier) -> (file: StaticString, line: UInt)? {
return nil
public func _promiseCompleted(futureIdentifier: _NIOEventLoopFutureIdentifier) -> (file: StaticString, line: UInt)?
{
nil
}
}
@@ -402,7 +404,7 @@ extension EventLoop {
extension EventLoopGroup {
public var description: String {
return String(describing: self)
String(describing: self)
}
}
@@ -416,7 +418,7 @@ public struct TimeAmount: Hashable, Sendable {
/// The nanoseconds representation of the `TimeAmount`.
public let nanoseconds: Int64
/* private but */ @inlinable
@inlinable
init(_ nanoseconds: Int64) {
self.nanoseconds = nanoseconds
}
@@ -428,7 +430,7 @@ public struct TimeAmount: Hashable, Sendable {
/// - returns: the `TimeAmount` for the given amount.
@inlinable
public static func nanoseconds(_ amount: Int64) -> TimeAmount {
return TimeAmount(amount)
TimeAmount(amount)
}
/// Creates a new `TimeAmount` for the given amount of microseconds.
@@ -440,7 +442,7 @@ public struct TimeAmount: Hashable, Sendable {
/// - note: returns `TimeAmount(.max)` if the amount overflows when converted to nanoseconds and `TimeAmount(.min)` if it underflows.
@inlinable
public static func microseconds(_ amount: Int64) -> TimeAmount {
return TimeAmount(_cappedNanoseconds(amount: amount, multiplier: 1000))
TimeAmount(_cappedNanoseconds(amount: amount, multiplier: 1000))
}
/// Creates a new `TimeAmount` for the given amount of milliseconds.
@@ -452,7 +454,7 @@ public struct TimeAmount: Hashable, Sendable {
/// - note: returns `TimeAmount(.max)` if the amount overflows when converted to nanoseconds and `TimeAmount(.min)` if it underflows.
@inlinable
public static func milliseconds(_ amount: Int64) -> TimeAmount {
return TimeAmount(_cappedNanoseconds(amount: amount, multiplier: 1000 * 1000))
TimeAmount(_cappedNanoseconds(amount: amount, multiplier: 1000 * 1000))
}
/// Creates a new `TimeAmount` for the given amount of seconds.
@@ -464,7 +466,7 @@ public struct TimeAmount: Hashable, Sendable {
/// - note: returns `TimeAmount(.max)` if the amount overflows when converted to nanoseconds and `TimeAmount(.min)` if it underflows.
@inlinable
public static func seconds(_ amount: Int64) -> TimeAmount {
return TimeAmount(_cappedNanoseconds(amount: amount, multiplier: 1000 * 1000 * 1000))
TimeAmount(_cappedNanoseconds(amount: amount, multiplier: 1000 * 1000 * 1000))
}
/// Creates a new `TimeAmount` for the given amount of minutes.
@@ -476,7 +478,7 @@ public struct TimeAmount: Hashable, Sendable {
/// - note: returns `TimeAmount(.max)` if the amount overflows when converted to nanoseconds and `TimeAmount(.min)` if it underflows.
@inlinable
public static func minutes(_ amount: Int64) -> TimeAmount {
return TimeAmount(_cappedNanoseconds(amount: amount, multiplier: 1000 * 1000 * 1000 * 60))
TimeAmount(_cappedNanoseconds(amount: amount, multiplier: 1000 * 1000 * 1000 * 60))
}
/// Creates a new `TimeAmount` for the given amount of hours.
@@ -488,9 +490,9 @@ public struct TimeAmount: Hashable, Sendable {
/// - note: returns `TimeAmount(.max)` if the amount overflows when converted to nanoseconds and `TimeAmount(.min)` if it underflows.
@inlinable
public static func hours(_ amount: Int64) -> TimeAmount {
return TimeAmount(_cappedNanoseconds(amount: amount, multiplier: 1000 * 1000 * 1000 * 60 * 60))
TimeAmount(_cappedNanoseconds(amount: amount, multiplier: 1000 * 1000 * 1000 * 60 * 60))
}
/// Converts `amount` to nanoseconds multiplying it by `multiplier`. The return value is capped to `Int64.max` if the multiplication overflows and `Int64.min` if it underflows.
///
/// - parameters:
@@ -511,7 +513,7 @@ public struct TimeAmount: Hashable, Sendable {
extension TimeAmount: Comparable {
@inlinable
public static func < (lhs: TimeAmount, rhs: TimeAmount) -> Bool {
return lhs.nanoseconds < rhs.nanoseconds
lhs.nanoseconds < rhs.nanoseconds
}
}
@@ -519,37 +521,37 @@ extension TimeAmount: AdditiveArithmetic {
/// The zero value for `TimeAmount`.
@inlinable
public static var zero: TimeAmount {
return TimeAmount.nanoseconds(0)
TimeAmount.nanoseconds(0)
}
@inlinable
public static func + (lhs: TimeAmount, rhs: TimeAmount) -> TimeAmount {
return TimeAmount(lhs.nanoseconds + rhs.nanoseconds)
TimeAmount(lhs.nanoseconds + rhs.nanoseconds)
}
@inlinable
public static func +=(lhs: inout TimeAmount, rhs: TimeAmount) {
public static func += (lhs: inout TimeAmount, rhs: TimeAmount) {
lhs = lhs + rhs
}
@inlinable
public static func - (lhs: TimeAmount, rhs: TimeAmount) -> TimeAmount {
return TimeAmount(lhs.nanoseconds - rhs.nanoseconds)
TimeAmount(lhs.nanoseconds - rhs.nanoseconds)
}
@inlinable
public static func -=(lhs: inout TimeAmount, rhs: TimeAmount) {
public static func -= (lhs: inout TimeAmount, rhs: TimeAmount) {
lhs = lhs - rhs
}
@inlinable
public static func * <T: BinaryInteger>(lhs: T, rhs: TimeAmount) -> TimeAmount {
return TimeAmount(Int64(lhs) * rhs.nanoseconds)
TimeAmount(Int64(lhs) * rhs.nanoseconds)
}
@inlinable
public static func * <T: BinaryInteger>(lhs: TimeAmount, rhs: T) -> TimeAmount {
return TimeAmount(lhs.nanoseconds * Int64(rhs))
TimeAmount(lhs.nanoseconds * Int64(rhs))
}
}
@@ -575,7 +577,7 @@ public struct NIODeadline: Equatable, Hashable, Sendable {
public typealias Value = UInt64
// This really should be an UInt63 but we model it as Int64 with >=0 assert
/* private but */ @usableFromInline var _uptimeNanoseconds: Int64 {
@usableFromInline var _uptimeNanoseconds: Int64 {
didSet {
assert(self._uptimeNanoseconds >= 0)
}
@@ -584,18 +586,17 @@ public struct NIODeadline: Equatable, Hashable, Sendable {
/// The nanoseconds since boot representation of the `NIODeadline`.
@inlinable
public var uptimeNanoseconds: UInt64 {
return .init(self._uptimeNanoseconds)
.init(self._uptimeNanoseconds)
}
public static let distantPast = NIODeadline(0)
public static let distantFuture = NIODeadline(.init(Int64.max))
/* private but */ @inlinable init(_ nanoseconds: Int64) {
@inlinable init(_ nanoseconds: Int64) {
precondition(nanoseconds >= 0)
self._uptimeNanoseconds = nanoseconds
}
/// Getting the time is a very common operation so it warrants optimization.
///
/// Prior to this function, NIO relied on `DispatchTime.now()`, on all platforms. In addition to
@@ -608,31 +609,31 @@ public struct NIODeadline: Equatable, Hashable, Sendable {
/// - TODO: Investigate optimizing the call to `DispatchTime.now()` away on other platforms too.
@inlinable
static func timeNow() -> UInt64 {
#if os(Linux)
#if os(Linux)
var ts = timespec()
clock_gettime(CLOCK_MONOTONIC, &ts)
/// We use unsafe arithmetic here because `UInt64.max` nanoseconds is more than 580 years,
/// and the odds that this code will still be running 530 years from now is very, very low,
/// so as a practical matter this will never overflow.
return UInt64(ts.tv_sec) &* 1_000_000_000 &+ UInt64(ts.tv_nsec)
#else // os(Linux)
#else // os(Linux)
return DispatchTime.now().uptimeNanoseconds
#endif // os(Linux)
#endif // os(Linux)
}
@inlinable
public static func now() -> NIODeadline {
return NIODeadline.uptimeNanoseconds(timeNow())
NIODeadline.uptimeNanoseconds(timeNow())
}
@inlinable
public static func uptimeNanoseconds(_ nanoseconds: UInt64) -> NIODeadline {
return NIODeadline(Int64(min(UInt64(Int64.max), nanoseconds)))
NIODeadline(Int64(min(UInt64(Int64.max), nanoseconds)))
}
@inlinable
public static func == (lhs: NIODeadline, rhs: NIODeadline) -> Bool {
return lhs.uptimeNanoseconds == rhs.uptimeNanoseconds
lhs.uptimeNanoseconds == rhs.uptimeNanoseconds
}
@inlinable
@@ -644,19 +645,19 @@ public struct NIODeadline: Equatable, Hashable, Sendable {
extension NIODeadline: Comparable {
@inlinable
public static func < (lhs: NIODeadline, rhs: NIODeadline) -> Bool {
return lhs.uptimeNanoseconds < rhs.uptimeNanoseconds
lhs.uptimeNanoseconds < rhs.uptimeNanoseconds
}
@inlinable
public static func > (lhs: NIODeadline, rhs: NIODeadline) -> Bool {
return lhs.uptimeNanoseconds > rhs.uptimeNanoseconds
lhs.uptimeNanoseconds > rhs.uptimeNanoseconds
}
}
extension NIODeadline: CustomStringConvertible {
@inlinable
public var description: String {
return self.uptimeNanoseconds.description
self.uptimeNanoseconds.description
}
}
@@ -665,7 +666,7 @@ extension NIODeadline {
public static func - (lhs: NIODeadline, rhs: NIODeadline) -> TimeAmount {
// This won't ever crash, NIODeadlines are guaranteed to be within 0 ..< 2^63-1 nanoseconds so the result can
// definitely be stored in a TimeAmount (which is an Int64).
return .nanoseconds(Int64(lhs.uptimeNanoseconds) - Int64(rhs.uptimeNanoseconds))
.nanoseconds(Int64(lhs.uptimeNanoseconds) - Int64(rhs.uptimeNanoseconds))
}
@inlinable
@@ -674,7 +675,7 @@ extension NIODeadline {
let overflow: Bool
(partial, overflow) = Int64(lhs.uptimeNanoseconds).addingReportingOverflow(rhs.nanoseconds)
if overflow {
assert(rhs.nanoseconds > 0) // this certainly must have overflowed towards +infinity
assert(rhs.nanoseconds > 0) // this certainly must have overflowed towards +infinity
return NIODeadline.distantFuture
}
guard partial >= 0 else {
@@ -807,7 +808,7 @@ extension EventLoop {
) -> Scheduled<T> {
self._flatScheduleTask(in: delay, file: file, line: line, task)
}
@usableFromInline typealias FlatScheduleTaskDelayCallback<T> = @Sendable () throws -> EventLoopFuture<T>
@inlinable
@@ -826,8 +827,12 @@ extension EventLoop {
/// Creates and returns a new `EventLoopPromise` that will be notified using this `EventLoop` as execution `NIOThread`.
@inlinable
public func makePromise<T>(of type: T.Type = T.self, file: StaticString = #fileID, line: UInt = #line) -> EventLoopPromise<T> {
return EventLoopPromise<T>(eventLoop: self, file: file, line: line)
public func makePromise<T>(
of type: T.Type = T.self,
file: StaticString = #fileID,
line: UInt = #line
) -> EventLoopPromise<T> {
EventLoopPromise<T>(eventLoop: self, file: file, line: line)
}
/// Creates and returns a new `EventLoopFuture` that is already marked as failed. Notifications will be done using this `EventLoop` as execution `NIOThread`.
@@ -837,7 +842,7 @@ extension EventLoop {
/// - returns: a failed `EventLoopFuture`.
@inlinable
public func makeFailedFuture<T>(_ error: Error) -> EventLoopFuture<T> {
return EventLoopFuture<T>(eventLoop: self, error: error)
EventLoopFuture<T>(eventLoop: self, error: error)
}
/// Creates and returns a new `EventLoopFuture` that is already marked as success. Notifications will be done using this `EventLoop` as execution `NIOThread`.
@@ -885,21 +890,20 @@ extension EventLoop {
///
/// - returns: Itself, because an `EventLoop` forms a singular `EventLoopGroup`.
public func next() -> EventLoop {
return self
self
}
/// An `EventLoop` forms a singular `EventLoopGroup`, returning itself as 'any' `EventLoop`.
///
/// - returns: Itself, because an `EventLoop` forms a singular `EventLoopGroup`.
public func any() -> EventLoop {
return self
self
}
/// Close this `EventLoop`.
public func close() throws {
// Do nothing
}
/// Schedule a repeated task to be executed by the `EventLoop` with a fixed delay between the end and start of each
/// task.
@@ -920,7 +924,7 @@ extension EventLoop {
) -> RepeatedTask {
self._scheduleRepeatedTask(initialDelay: initialDelay, delay: delay, notifying: promise, task)
}
/// Schedule a repeated task to be executed by the `EventLoop` with a fixed delay between the end and start of each
/// task.
///
@@ -939,9 +943,17 @@ extension EventLoop {
notifying promise: EventLoopPromise<Void>? = nil,
_ task: @escaping @Sendable (RepeatedTask) throws -> Void
) -> RepeatedTask {
let jitteredInitialDelay = Self._getJitteredDelay(delay: initialDelay, maximumAllowableJitter: maximumAllowableJitter)
let jitteredInitialDelay = Self._getJitteredDelay(
delay: initialDelay,
maximumAllowableJitter: maximumAllowableJitter
)
let jitteredDelay = Self._getJitteredDelay(delay: delay, maximumAllowableJitter: maximumAllowableJitter)
return self.scheduleRepeatedTask(initialDelay: jitteredInitialDelay, delay: jitteredDelay, notifying: promise, task)
return self.scheduleRepeatedTask(
initialDelay: jitteredInitialDelay,
delay: jitteredDelay,
notifying: promise,
task
)
}
typealias ScheduleRepeatedTaskCallback = @Sendable (RepeatedTask) throws -> Void
@@ -961,7 +973,7 @@ extension EventLoop {
}
return self.scheduleRepeatedAsyncTask(initialDelay: initialDelay, delay: delay, notifying: promise, futureTask)
}
/// Schedule a repeated asynchronous task to be executed by the `EventLoop` with a fixed delay between the end and
/// start of each task.
///
@@ -988,7 +1000,7 @@ extension EventLoop {
) -> RepeatedTask {
self._scheduleRepeatedAsyncTask(initialDelay: initialDelay, delay: delay, notifying: promise, task)
}
/// Schedule a repeated asynchronous task to be executed by the `EventLoop` with a fixed delay between the end and
/// start of each task.
///
@@ -1014,9 +1026,17 @@ extension EventLoop {
notifying promise: EventLoopPromise<Void>? = nil,
_ task: @escaping @Sendable (RepeatedTask) -> EventLoopFuture<Void>
) -> RepeatedTask {
let jitteredInitialDelay = Self._getJitteredDelay(delay: initialDelay, maximumAllowableJitter: maximumAllowableJitter)
let jitteredInitialDelay = Self._getJitteredDelay(
delay: initialDelay,
maximumAllowableJitter: maximumAllowableJitter
)
let jitteredDelay = Self._getJitteredDelay(delay: delay, maximumAllowableJitter: maximumAllowableJitter)
return self._scheduleRepeatedAsyncTask(initialDelay: jitteredInitialDelay, delay: jitteredDelay, notifying: promise, task)
return self._scheduleRepeatedAsyncTask(
initialDelay: jitteredInitialDelay,
delay: jitteredDelay,
notifying: promise,
task
)
}
typealias ScheduleRepeatedAsyncTaskCallback = @Sendable (RepeatedTask) -> EventLoopFuture<Void>
@@ -1043,14 +1063,14 @@ extension EventLoop {
maximumAllowableJitter: TimeAmount
) -> TimeAmount {
let jitter = TimeAmount.nanoseconds(Int64.random(in: .zero..<maximumAllowableJitter.nanoseconds))
return delay + jitter;
return delay + jitter
}
/// Returns an `EventLoopIterator` over this `EventLoop`.
///
/// - returns: `EventLoopIterator`
public func makeIterator() -> EventLoopIterator {
return EventLoopIterator([self])
EventLoopIterator([self])
}
/// Asserts that the current thread is the one tied to this `EventLoop`.
@@ -1127,7 +1147,7 @@ public protocol EventLoopGroup: AnyObject, _NIOPreconcurrencySendable {
/// The rule of thumb is: If you are trying to do _load balancing_, use `next()`. If you just want to create a new
/// future or kick off some operation, use `any()`.
func any() -> EventLoop
/// Shuts down the eventloop gracefully. This function is clearly an outlier in that it uses a completion
/// callback instead of an EventLoopFuture. The reason for that is that NIO's EventLoopFutures will call back on an event loop.
/// The virtue of this function is to shut the event loop down. To work around that we call back on a DispatchQueue
@@ -1150,7 +1170,7 @@ extension EventLoopGroup {
/// The default implementation of `any()` just returns the `next()` EventLoop but it's highly recommended to
/// override this and return the current `EventLoop` if possible.
public func any() -> EventLoop {
return self.next()
self.next()
}
}
@@ -120,7 +120,7 @@ struct IsolatedEventLoop {
/// Returns the wrapped event loop.
@inlinable
func nonisolated() -> any EventLoop {
return self._wrapped
self._wrapped
}
}
extension EventLoop {
@@ -421,8 +421,8 @@ extension EventLoopFuture {
@inlinable
func unwrap<NewValue>(
orReplace replacement: NewValue
) -> EventLoopFuture<NewValue>.Isolated where Value == Optional<NewValue> {
return self.map { (value) -> NewValue in
) -> EventLoopFuture<NewValue>.Isolated where Value == NewValue? {
self.map { (value) -> NewValue in
guard let value = value else {
return replacement
}
@@ -447,8 +447,8 @@ extension EventLoopFuture {
@inlinable
func unwrap<NewValue>(
orElse callback: @escaping () -> NewValue
) -> EventLoopFuture<NewValue>.Isolated where Value == Optional<NewValue> {
return self.map { (value) -> NewValue in
) -> EventLoopFuture<NewValue>.Isolated where Value == NewValue? {
self.map { (value) -> NewValue in
guard let value = value else {
return callback()
}
@@ -459,7 +459,7 @@ extension EventLoopFuture {
/// Returns the wrapped event loop future.
@inlinable
func nonisolated() -> EventLoopFuture<Value> {
return self._wrapped
self._wrapped
}
}
@@ -471,7 +471,6 @@ extension EventLoopFuture {
}
}
extension EventLoopPromise {
/// A struct wrapping an ``EventLoopPromise`` that ensures all calls to any method on this struct
/// are coming from the event loop of the promise.
@@ -480,7 +479,6 @@ extension EventLoopPromise {
@usableFromInline
let _wrapped: EventLoopPromise<Value>
/// Deliver a successful result to the associated `EventLoopFuture<Value>` object.
///
/// - parameters:
@@ -514,7 +512,7 @@ extension EventLoopPromise {
/// Returns the wrapped event loop promise.
@inlinable
func nonisolated() -> EventLoopPromise<Value> {
return self._wrapped
self._wrapped
}
}
@@ -525,4 +523,3 @@ extension EventLoopPromise {
return Isolated(_wrapped: self)
}
}
@@ -15,63 +15,91 @@
extension EventLoopFuture {
@inlinable
@available(*, deprecated, message: "Please don't pass file:line:, there's no point.")
public func flatMap<NewValue>(file: StaticString = #fileID, line: UInt = #line, _ callback: @escaping (Value) -> EventLoopFuture<NewValue>) -> EventLoopFuture<NewValue> {
return self.flatMap(callback)
public func flatMap<NewValue>(
file: StaticString = #fileID,
line: UInt = #line,
_ callback: @escaping (Value) -> EventLoopFuture<NewValue>
) -> EventLoopFuture<NewValue> {
self.flatMap(callback)
}
@inlinable
@available(*, deprecated, message: "Please don't pass file:line:, there's no point.")
public func flatMapThrowing<NewValue>(file: StaticString = #fileID,
line: UInt = #line,
_ callback: @escaping (Value) throws -> NewValue) -> EventLoopFuture<NewValue> {
return self.flatMapThrowing(callback)
public func flatMapThrowing<NewValue>(
file: StaticString = #fileID,
line: UInt = #line,
_ callback: @escaping (Value) throws -> NewValue
) -> EventLoopFuture<NewValue> {
self.flatMapThrowing(callback)
}
@inlinable
@available(*, deprecated, message: "Please don't pass file:line:, there's no point.")
public func flatMapErrorThrowing(file: StaticString = #fileID, line: UInt = #line, _ callback: @escaping (Error) throws -> Value) -> EventLoopFuture<Value> {
return self.flatMapErrorThrowing(callback)
public func flatMapErrorThrowing(
file: StaticString = #fileID,
line: UInt = #line,
_ callback: @escaping (Error) throws -> Value
) -> EventLoopFuture<Value> {
self.flatMapErrorThrowing(callback)
}
@inlinable
@available(*, deprecated, message: "Please don't pass file:line:, there's no point.")
public func map<NewValue>(file: StaticString = #fileID, line: UInt = #line, _ callback: @escaping (Value) -> (NewValue)) -> EventLoopFuture<NewValue> {
return self.map(callback)
public func map<NewValue>(
file: StaticString = #fileID,
line: UInt = #line,
_ callback: @escaping (Value) -> (NewValue)
) -> EventLoopFuture<NewValue> {
self.map(callback)
}
@inlinable
@available(*, deprecated, message: "Please don't pass file:line:, there's no point.")
public func flatMapError(file: StaticString = #fileID, line: UInt = #line, _ callback: @escaping (Error) -> EventLoopFuture<Value>) -> EventLoopFuture<Value> {
return self.flatMapError(callback)
public func flatMapError(
file: StaticString = #fileID,
line: UInt = #line,
_ callback: @escaping (Error) -> EventLoopFuture<Value>
) -> EventLoopFuture<Value> {
self.flatMapError(callback)
}
@inlinable
@available(*, deprecated, message: "Please don't pass file:line:, there's no point.")
public func flatMapResult<NewValue, SomeError: Error>(file: StaticString = #fileID,
line: UInt = #line,
_ body: @escaping (Value) -> Result<NewValue, SomeError>) -> EventLoopFuture<NewValue> {
return self.flatMapResult(body)
public func flatMapResult<NewValue, SomeError: Error>(
file: StaticString = #fileID,
line: UInt = #line,
_ body: @escaping (Value) -> Result<NewValue, SomeError>
) -> EventLoopFuture<NewValue> {
self.flatMapResult(body)
}
@inlinable
@available(*, deprecated, message: "Please don't pass file:line:, there's no point.")
public func recover(file: StaticString = #fileID, line: UInt = #line, _ callback: @escaping (Error) -> Value) -> EventLoopFuture<Value> {
return self.recover(callback)
public func recover(
file: StaticString = #fileID,
line: UInt = #line,
_ callback: @escaping (Error) -> Value
) -> EventLoopFuture<Value> {
self.recover(callback)
}
@inlinable
@available(*, deprecated, message: "Please don't pass file:line:, there's no point.")
public func and<OtherValue>(_ other: EventLoopFuture<OtherValue>,
file: StaticString = #fileID,
line: UInt = #line) -> EventLoopFuture<(Value, OtherValue)> {
return self.and(other)
public func and<OtherValue>(
_ other: EventLoopFuture<OtherValue>,
file: StaticString = #fileID,
line: UInt = #line
) -> EventLoopFuture<(Value, OtherValue)> {
self.and(other)
}
@inlinable
@available(*, deprecated, message: "Please don't pass file:line:, there's no point.")
public func and<OtherValue>(value: OtherValue,
file: StaticString = #fileID,
line: UInt = #line) -> EventLoopFuture<(Value, OtherValue)> {
return self.and(value: value)
public func and<OtherValue>(
value: OtherValue,
file: StaticString = #fileID,
line: UInt = #line
) -> EventLoopFuture<(Value, OtherValue)> {
self.and(value: value)
}
}
@@ -41,7 +41,9 @@ extension EventLoopFuture {
/// - returns: A future that will receive the eventual value.
@inlinable
@preconcurrency
public func flatMapWithEventLoop<NewValue>(_ callback: @escaping @Sendable (Value, EventLoop) -> EventLoopFuture<NewValue>) -> EventLoopFuture<NewValue> {
public func flatMapWithEventLoop<NewValue>(
_ callback: @escaping @Sendable (Value, EventLoop) -> EventLoopFuture<NewValue>
) -> EventLoopFuture<NewValue> {
let next = EventLoopPromise<NewValue>.makeUnleakablePromise(eventLoop: self.eventLoop)
self._whenComplete { [eventLoop = self.eventLoop] in
switch self._value! {
@@ -61,7 +63,7 @@ extension EventLoopFuture {
}
return next.futureResult
}
/// When the current `EventLoopFuture<Value>` is in an error state, run the provided callback, which
/// may recover from the error by returning an `EventLoopFuture<NewValue>`. The callback is intended to potentially
/// recover from the error by returning a new `EventLoopFuture` that will eventually contain the recovered
@@ -75,7 +77,9 @@ extension EventLoopFuture {
/// - returns: A future that will receive the recovered value.
@inlinable
@preconcurrency
public func flatMapErrorWithEventLoop(_ callback: @escaping @Sendable (Error, EventLoop) -> EventLoopFuture<Value>) -> EventLoopFuture<Value> {
public func flatMapErrorWithEventLoop(
_ callback: @escaping @Sendable (Error, EventLoop) -> EventLoopFuture<Value>
) -> EventLoopFuture<Value> {
let next = EventLoopPromise<Value>.makeUnleakablePromise(eventLoop: self.eventLoop)
self._whenComplete { [eventLoop = self.eventLoop] in
switch self._value! {
@@ -119,7 +123,8 @@ extension EventLoopFuture {
with combiningFunction: @escaping @Sendable (Value, OtherValue, EventLoop) -> EventLoopFuture<Value>
) -> EventLoopFuture<Value> {
func fold0(eventLoop: EventLoop) -> EventLoopFuture<Value> {
let body = futures.reduce(self) { (f1: EventLoopFuture<Value>, f2: EventLoopFuture<OtherValue>) -> EventLoopFuture<Value> in
let body = futures.reduce(self) {
(f1: EventLoopFuture<Value>, f2: EventLoopFuture<OtherValue>) -> EventLoopFuture<Value> in
let newFuture = f1.and(f2).flatMap { (args: (Value, OtherValue)) -> EventLoopFuture<Value> in
let (f1Value, f2Value) = args
self.eventLoop.assertInEventLoop()
+106 -62
View File
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
import NIOConcurrencyHelpers
import Dispatch
import NIOConcurrencyHelpers
/// Internal list of callbacks.
///
@@ -158,9 +158,11 @@ public struct EventLoopPromise<Value> {
@inlinable
internal static func makeUnleakablePromise(eventLoop: EventLoop, line: UInt = #line) -> EventLoopPromise<Value> {
return EventLoopPromise<Value>(eventLoop: eventLoop,
file: "BUG in SwiftNIO (please report), unleakable promise leaked.",
line: line)
EventLoopPromise<Value>(
eventLoop: eventLoop,
file: "BUG in SwiftNIO (please report), unleakable promise leaked.",
line: line
)
}
/// General initializer
@@ -196,7 +198,7 @@ public struct EventLoopPromise<Value> {
///
/// This method is equivalent to invoking `future.cascade(to: promise)`,
/// but sometimes may read better than its cascade counterpart.
///
///
/// - parameters:
/// - future: The future whose value will be used to succeed or fail this promise.
/// - seealso: `EventLoopFuture.cascade(to:)`
@@ -250,7 +252,7 @@ public struct EventLoopPromise<Value> {
/// - returns: The callback list to run.
@inlinable
internal func _setValue(value: Result<Value, Error>) -> CallbackList {
return self.futureResult._setValue(value: value)
self.futureResult._setValue(value: value)
}
}
@@ -432,8 +434,8 @@ public final class EventLoopFuture<Value> {
}
extension EventLoopFuture: Equatable {
public static func ==(lhs: EventLoopFuture, rhs: EventLoopFuture) -> Bool {
return lhs === rhs
public static func == (lhs: EventLoopFuture, rhs: EventLoopFuture) -> Bool {
lhs === rhs
}
}
@@ -470,7 +472,9 @@ extension EventLoopFuture {
/// - returns: A future that will receive the eventual value.
@inlinable
@preconcurrency
public func flatMap<NewValue>(_ callback: @escaping @Sendable (Value) -> EventLoopFuture<NewValue>) -> EventLoopFuture<NewValue> {
public func flatMap<NewValue>(
_ callback: @escaping @Sendable (Value) -> EventLoopFuture<NewValue>
) -> EventLoopFuture<NewValue> {
self._flatMap(callback)
}
@usableFromInline typealias FlatMapCallback<NewValue> = @Sendable (Value) -> EventLoopFuture<NewValue>
@@ -513,13 +517,17 @@ extension EventLoopFuture {
/// - returns: A future that will receive the eventual value.
@inlinable
@preconcurrency
public func flatMapThrowing<NewValue>(_ callback: @escaping @Sendable (Value) throws -> NewValue) -> EventLoopFuture<NewValue> {
public func flatMapThrowing<NewValue>(
_ callback: @escaping @Sendable (Value) throws -> NewValue
) -> EventLoopFuture<NewValue> {
self._flatMapThrowing(callback)
}
@usableFromInline typealias FlatMapThrowingCallback<NewValue> = @Sendable (Value) throws -> NewValue
@inlinable
func _flatMapThrowing<NewValue>(_ callback: @escaping FlatMapThrowingCallback<NewValue>) -> EventLoopFuture<NewValue> {
func _flatMapThrowing<NewValue>(
_ callback: @escaping FlatMapThrowingCallback<NewValue>
) -> EventLoopFuture<NewValue> {
let next = EventLoopPromise<NewValue>.makeUnleakablePromise(eventLoop: self.eventLoop)
self._whenComplete {
switch self._value! {
@@ -553,7 +561,8 @@ extension EventLoopFuture {
/// - returns: A future that will receive the eventual value or a rethrown error.
@inlinable
@preconcurrency
public func flatMapErrorThrowing(_ callback: @escaping @Sendable (Error) throws -> Value) -> EventLoopFuture<Value> {
public func flatMapErrorThrowing(_ callback: @escaping @Sendable (Error) throws -> Value) -> EventLoopFuture<Value>
{
self._flatMapErrorThrowing(callback)
}
@usableFromInline typealias FlatMapErrorThrowingCallback = @Sendable (Error) throws -> Value
@@ -618,7 +627,7 @@ extension EventLoopFuture {
} else {
let next = EventLoopPromise<NewValue>.makeUnleakablePromise(eventLoop: self.eventLoop)
self._whenComplete {
return next._setValue(value: self._value!.map(callback))
next._setValue(value: self._value!.map(callback))
}
return next.futureResult
}
@@ -637,7 +646,9 @@ extension EventLoopFuture {
/// - returns: A future that will receive the recovered value.
@inlinable
@preconcurrency
public func flatMapError(_ callback: @escaping @Sendable (Error) -> EventLoopFuture<Value>) -> EventLoopFuture<Value> {
public func flatMapError(
_ callback: @escaping @Sendable (Error) -> EventLoopFuture<Value>
) -> EventLoopFuture<Value> {
self._flatMapError(callback)
}
@usableFromInline typealias FlatMapErrorCallback = @Sendable (Error) -> EventLoopFuture<Value>
@@ -679,13 +690,19 @@ extension EventLoopFuture {
/// - returns: A future that will receive the eventual value.
@inlinable
@preconcurrency
public func flatMapResult<NewValue, SomeError: Error>(_ body: @escaping @Sendable (Value) -> Result<NewValue, SomeError>) -> EventLoopFuture<NewValue> {
public func flatMapResult<NewValue, SomeError: Error>(
_ body: @escaping @Sendable (Value) -> Result<NewValue, SomeError>
) -> EventLoopFuture<NewValue> {
self._flatMapResult(body)
}
@usableFromInline typealias FlatMapResultCallback<NewValue, SomeError: Error> = @Sendable (Value) -> Result<NewValue, SomeError>
@usableFromInline typealias FlatMapResultCallback<NewValue, SomeError: Error> = @Sendable (Value) -> Result<
NewValue, SomeError
>
@inlinable
func _flatMapResult<NewValue, SomeError: Error>(_ body: @escaping FlatMapResultCallback<NewValue, SomeError>) -> EventLoopFuture<NewValue> {
func _flatMapResult<NewValue, SomeError: Error>(
_ body: @escaping FlatMapResultCallback<NewValue, SomeError>
) -> EventLoopFuture<NewValue> {
let next = EventLoopPromise<NewValue>.makeUnleakablePromise(eventLoop: self.eventLoop)
self._whenComplete {
switch self._value! {
@@ -750,7 +767,8 @@ extension EventLoopFuture {
/// Add a callback. If there's already a value, run as much of the chain as we can.
@inlinable
@preconcurrency // TODO: We want to remove @preconcurrency but it results in more allocations in 1000_udpconnections
// TODO: We want to remove @preconcurrency but it results in more allocations in 1000_udpconnections
@preconcurrency
internal func _whenComplete(_ callback: @escaping @Sendable () -> CallbackList) {
self._internalWhenComplete(callback)
}
@@ -865,7 +883,7 @@ extension EventLoopFuture {
@inlinable
public func and<OtherValue>(_ other: EventLoopFuture<OtherValue>) -> EventLoopFuture<(Value, OtherValue)> {
let promise = EventLoopPromise<(Value, OtherValue)>.makeUnleakablePromise(eventLoop: self.eventLoop)
let box: UnsafeMutableTransferBox<(t:Value?, u: OtherValue?)> = .init((nil, nil))
let box: UnsafeMutableTransferBox<(t: Value?, u: OtherValue?)> = .init((nil, nil))
assert(self.eventLoop === promise.futureResult.eventLoop)
self._whenComplete { () -> CallbackList in
@@ -905,7 +923,7 @@ extension EventLoopFuture {
/// This is just syntactic sugar for `future.and(loop.makeSucceedFuture(value))`.
@inlinable
public func and<OtherValue>(value: OtherValue) -> EventLoopFuture<(Value, OtherValue)> {
return self.and(EventLoopFuture<OtherValue>(eventLoop: self.eventLoop, value: value))
self.and(EventLoopFuture<OtherValue>(eventLoop: self.eventLoop, value: value))
}
}
@@ -994,7 +1012,7 @@ extension EventLoopFuture {
@available(*, noasync, message: "wait() can block indefinitely, prefer get()", renamed: "get()")
@inlinable
public func wait(file: StaticString = #file, line: UInt = #line) throws -> Value {
return try self._wait(file: file, line: line)
try self._wait(file: file, line: line)
}
@inlinable
@@ -1012,7 +1030,7 @@ extension EventLoopFuture {
lock.lock(whenValue: 1)
lock.unlock()
switch(v.wrappedValue!) {
switch v.wrappedValue! {
case .success(let result):
return result
case .failure(let error):
@@ -1056,7 +1074,8 @@ extension EventLoopFuture {
with combiningFunction: @escaping FoldCallback<OtherValue>
) -> EventLoopFuture<Value> {
func fold0() -> EventLoopFuture<Value> {
let body = futures.reduce(self) { (f1: EventLoopFuture<Value>, f2: EventLoopFuture<OtherValue>) -> EventLoopFuture<Value> in
let body = futures.reduce(self) {
(f1: EventLoopFuture<Value>, f2: EventLoopFuture<OtherValue>) -> EventLoopFuture<Value> in
let newFuture = f1.and(f2).flatMap { (args: (Value, OtherValue)) -> EventLoopFuture<Value> in
let (f1Value, f2Value) = args
self.eventLoop.assertInEventLoop()
@@ -1106,9 +1125,9 @@ extension EventLoopFuture {
@inlinable
public static func reduce<InputValue>(
_ initialResult: Value,
_ futures: [EventLoopFuture<InputValue>],
on eventLoop: EventLoop,
_ nextPartialResult: @escaping @Sendable (Value, InputValue) -> Value
_ futures: [EventLoopFuture<InputValue>],
on eventLoop: EventLoop,
_ nextPartialResult: @escaping @Sendable (Value, InputValue) -> Value
) -> EventLoopFuture<Value> {
Self._reduce(initialResult, futures, on: eventLoop, nextPartialResult)
}
@@ -1203,7 +1222,10 @@ extension EventLoopFuture {
/// - on: The `EventLoop` on which the new `EventLoopFuture` callbacks will execute on.
/// - Returns: A new `EventLoopFuture` that waits for the other futures to succeed.
@inlinable
public static func andAllSucceed(_ futures: [EventLoopFuture<Value>], on eventLoop: EventLoop) -> EventLoopFuture<Void> {
public static func andAllSucceed(
_ futures: [EventLoopFuture<Value>],
on eventLoop: EventLoop
) -> EventLoopFuture<Void> {
let promise = eventLoop.makePromise(of: Void.self)
EventLoopFuture.andAllSucceed(futures, promise: promise)
return promise.futureResult
@@ -1238,7 +1260,10 @@ extension EventLoopFuture {
/// - futures: An array of homogenous `EventLoopFuture`s to wait on for fulfilled values.
/// - on: The `EventLoop` on which the new `EventLoopFuture` callbacks will fire.
/// - Returns: A new `EventLoopFuture` with all of the values fulfilled by the provided futures.
public static func whenAllSucceed(_ futures: [EventLoopFuture<Value>], on eventLoop: EventLoop) -> EventLoopFuture<[Value]> {
public static func whenAllSucceed(
_ futures: [EventLoopFuture<Value>],
on eventLoop: EventLoop
) -> EventLoopFuture<[Value]> {
let promise = eventLoop.makePromise(of: [Value].self)
EventLoopFuture.whenAllSucceed(futures, promise: promise)
return promise.futureResult
@@ -1272,7 +1297,7 @@ extension EventLoopFuture {
reduced.futureResult.whenComplete { result in
switch result {
case .success:
// verify that all operations have been completed
// verify that all operations have been completed
assert(!results.wrappedValue.contains(where: { $0 == nil }))
promise.succeed(results.wrappedValue.map { $0! })
case .failure(let error):
@@ -1321,7 +1346,8 @@ extension EventLoopFuture {
// in the "futures" to pass their result to the caller
for (index, future) in futures.enumerated() {
if future.eventLoop.inEventLoop,
let result = future._value {
let result = future._value
{
// Fast-track already-fulfilled results without the overhead of calling `whenComplete`. This can yield a
// ~20% performance improvement in the case of large arrays where all elements are already fulfilled.
processResult(index, result)
@@ -1350,7 +1376,10 @@ extension EventLoopFuture {
/// - on: The `EventLoop` on which the new `EventLoopFuture` callbacks will execute on.
/// - Returns: A new `EventLoopFuture` that succeeds after all futures complete.
@inlinable
public static func andAllComplete(_ futures: [EventLoopFuture<Value>], on eventLoop: EventLoop) -> EventLoopFuture<Void> {
public static func andAllComplete(
_ futures: [EventLoopFuture<Value>],
on eventLoop: EventLoop
) -> EventLoopFuture<Void> {
let promise = eventLoop.makePromise(of: Void.self)
EventLoopFuture.andAllComplete(futures, promise: promise)
return promise.futureResult
@@ -1390,8 +1419,10 @@ extension EventLoopFuture {
/// - on: The `EventLoop` on which the new `EventLoopFuture` callbacks will fire.
/// - Returns: A new `EventLoopFuture` with all the results of the provided futures.
@inlinable
public static func whenAllComplete(_ futures: [EventLoopFuture<Value>],
on eventLoop: EventLoop) -> EventLoopFuture<[Result<Value, Error>]> {
public static func whenAllComplete(
_ futures: [EventLoopFuture<Value>],
on eventLoop: EventLoop
) -> EventLoopFuture<[Result<Value, Error>]> {
let promise = eventLoop.makePromise(of: [Result<Value, Error>].self)
EventLoopFuture.whenAllComplete(futures, promise: promise)
return promise.futureResult
@@ -1405,12 +1436,16 @@ extension EventLoopFuture {
/// - futures: An array of homogenous `EventLoopFuture`s to gather results from.
/// - promise: The `EventLoopPromise` to complete with the result of the futures.
@inlinable
public static func whenAllComplete(_ futures: [EventLoopFuture<Value>],
promise: EventLoopPromise<[Result<Value, Error>]>) {
public static func whenAllComplete(
_ futures: [EventLoopFuture<Value>],
promise: EventLoopPromise<[Result<Value, Error>]>
) {
let eventLoop = promise.futureResult.eventLoop
let reduced = eventLoop.makePromise(of: Void.self)
let results: UnsafeMutableTransferBox<[Result<Value, Error>]> = .init(.init(repeating: .failure(OperationPlaceholderError()), count: futures.count))
let results: UnsafeMutableTransferBox<[Result<Value, Error>]> = .init(
.init(repeating: .failure(OperationPlaceholderError()), count: futures.count)
)
let callback = { @Sendable (index: Int, result: Result<Value, Error>) in
results.wrappedValue[index] = result
}
@@ -1427,10 +1462,12 @@ extension EventLoopFuture {
switch result {
case .success:
// verify that all operations have been completed
assert(!results.wrappedValue.contains(where: {
guard case let .failure(error) = $0 else { return false }
return error is OperationPlaceholderError
}))
assert(
!results.wrappedValue.contains(where: {
guard case let .failure(error) = $0 else { return false }
return error is OperationPlaceholderError
})
)
promise.succeed(results.wrappedValue)
case .failure(let error):
@@ -1474,7 +1511,8 @@ extension EventLoopFuture {
// in the "futures" to pass their result to the caller
for (index, future) in futures.enumerated() {
if future.eventLoop.inEventLoop,
let result = future._value {
let result = future._value
{
// Fast-track already-fulfilled results without the overhead of calling `whenComplete`. This can yield a
// ~30% performance improvement in the case of large arrays where all elements are already fulfilled.
processResult(index, result)
@@ -1519,7 +1557,7 @@ extension EventLoopFuture {
/// `EventLoopFuture` has any result.
///
/// - parameters:
/// - callback: the callback that is called when the `EventLoopFuture` is fulfilled.
/// - callback: the callback that is called when the `EventLoopFuture` is fulfilled.
/// - returns: the current `EventLoopFuture`
@inlinable
@preconcurrency
@@ -1557,8 +1595,8 @@ extension EventLoopFuture {
/// future.
/// - throws: the `Error` passed in the `orError` parameter when the resolved future's value is `Optional.none`.
@inlinable
public func unwrap<NewValue>(orError error: Error) -> EventLoopFuture<NewValue> where Value == Optional<NewValue> {
return self.flatMapThrowing { (value) throws -> NewValue in
public func unwrap<NewValue>(orError error: Error) -> EventLoopFuture<NewValue> where Value == NewValue? {
self.flatMapThrowing { (value) throws -> NewValue in
guard let value = value else {
throw error
}
@@ -1578,12 +1616,13 @@ extension EventLoopFuture {
/// - orReplace: the value of the returned `EventLoopFuture` when then resolved future's value is `Optional.some()`.
/// - returns: an new `EventLoopFuture` with new type parameter `NewValue` and the value passed in the `orReplace` parameter.
@inlinable
public func unwrap<NewValue>(orReplace replacement: NewValue) -> EventLoopFuture<NewValue> where Value == Optional<NewValue> {
return self.map { (value) -> NewValue in
public func unwrap<NewValue>(orReplace replacement: NewValue) -> EventLoopFuture<NewValue>
where Value == NewValue? {
self.map { (value) -> NewValue in
guard let value = value else {
return replacement
}
return value
return value
}
}
@@ -1605,7 +1644,7 @@ extension EventLoopFuture {
@preconcurrency
public func unwrap<NewValue>(
orElse callback: @escaping @Sendable () -> NewValue
) -> EventLoopFuture<NewValue> where Value == Optional<NewValue> {
) -> EventLoopFuture<NewValue> where Value == NewValue? {
self._unwrap(orElse: callback)
}
@usableFromInline typealias UnwrapCallback<NewValue> = @Sendable () -> NewValue
@@ -1613,8 +1652,8 @@ extension EventLoopFuture {
@inlinable
func _unwrap<NewValue>(
orElse callback: @escaping UnwrapCallback<NewValue>
) -> EventLoopFuture<NewValue> where Value == Optional<NewValue> {
return self.map { (value) -> NewValue in
) -> EventLoopFuture<NewValue> where Value == NewValue? {
self.map { (value) -> NewValue in
guard let value = value else {
return callback()
}
@@ -1623,7 +1662,7 @@ extension EventLoopFuture {
}
}
// MARK: may block
// MARK: may block
extension EventLoopFuture {
/// Chain an `EventLoopFuture<NewValue>` providing the result of a IO / task that may block. For example:
@@ -1651,7 +1690,7 @@ extension EventLoopFuture {
onto queue: DispatchQueue,
_ callbackMayBlock: @escaping FlatMapBlockingCallback<NewValue>
) -> EventLoopFuture<NewValue> {
return self.flatMap { result in
self.flatMap { result in
queue.asyncWithFuture(eventLoop: self.eventLoop) { try callbackMayBlock(result) }
}
}
@@ -1687,7 +1726,8 @@ extension EventLoopFuture {
/// - callbackMayBlock: The callback that is called with the failed result of the `EventLoopFuture`.
@inlinable
@preconcurrency
public func whenFailureBlocking(onto queue: DispatchQueue, _ callbackMayBlock: @escaping @Sendable (Error) -> Void) {
public func whenFailureBlocking(onto queue: DispatchQueue, _ callbackMayBlock: @escaping @Sendable (Error) -> Void)
{
self._whenFailureBlocking(onto: queue, callbackMayBlock)
}
@usableFromInline typealias WhenFailureBlockingCallback = @Sendable (Error) -> Void
@@ -1707,7 +1747,10 @@ extension EventLoopFuture {
/// - callbackMayBlock: The callback that is called when the `EventLoopFuture` is fulfilled.
@inlinable
@preconcurrency
public func whenCompleteBlocking(onto queue: DispatchQueue, _ callbackMayBlock: @escaping @Sendable (Result<Value, Error>) -> Void) {
public func whenCompleteBlocking(
onto queue: DispatchQueue,
_ callbackMayBlock: @escaping @Sendable (Result<Value, Error>) -> Void
) {
self._whenCompleteBlocking(onto: queue, callbackMayBlock)
}
@usableFromInline typealias WhenCompleteBlocking = @Sendable (Result<Value, Error>) -> Void
@@ -1733,7 +1776,7 @@ extension EventLoopFuture {
/// - line: The line this function was called on, for debugging purposes.
@inlinable
public func assertSuccess(file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Value> {
return self.always { result in
self.always { result in
switch result {
case .success:
()
@@ -1752,7 +1795,7 @@ extension EventLoopFuture {
/// - line: The line this function was called on, for debugging purposes.
@inlinable
public func assertFailure(file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Value> {
return self.always { result in
self.always { result in
switch result {
case .success(let value):
assertionFailure("Expected failure, but got success: \(value)", file: file, line: line)
@@ -1772,7 +1815,7 @@ extension EventLoopFuture {
/// - line: The line this function was called on, for debugging purposes.
@inlinable
public func preconditionSuccess(file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Value> {
return self.always { result in
self.always { result in
switch result {
case .success:
()
@@ -1792,7 +1835,7 @@ extension EventLoopFuture {
/// - line: The line this function was called on, for debugging purposes.
@inlinable
public func preconditionFailure(file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Value> {
return self.always { result in
self.always { result in
switch result {
case .success(let value):
Swift.preconditionFailure("Expected failure, but got success: \(value)", file: file, line: line)
@@ -1821,17 +1864,17 @@ public struct _NIOEventLoopFutureIdentifier: Hashable, Sendable {
// 1. 0xbf15ca5d is randomly picked such that it fits into both 32 and 64 bit address spaces
// 2. XOR with 0xbf15ca5d so that Memory Graph Debugger and other memory debugging tools
// won't see it as a reference.
return UInt(bitPattern: ObjectIdentifier(future)) ^ 0xbf15ca5d
UInt(bitPattern: ObjectIdentifier(future)) ^ 0xbf15_ca5d
}
}
// EventLoopPromise is a reference type, but by its very nature is Sendable (if its Value is).
extension EventLoopPromise: Sendable where Value: Sendable { }
extension EventLoopPromise: Sendable where Value: Sendable {}
// EventLoopFuture is a reference type, but it is Sendable (if its Value is). However, we enforce
// that by way of the guarantees of the EventLoop protocol, so the compiler cannot
// check it.
extension EventLoopFuture: @unchecked Sendable where Value: Sendable { }
extension EventLoopFuture: @unchecked Sendable where Value: Sendable {}
extension EventLoopPromise where Value == Void {
// Deliver a successful result to the associated `EventLoopFuture<Void>` object.
@@ -1849,7 +1892,8 @@ extension Optional {
/// to `promise`.
///
/// - Parameter promise: The promise to set or cascade to.
public mutating func setOrCascade<Value>(to promise: EventLoopPromise<Value>?) where Wrapped == EventLoopPromise<Value> {
public mutating func setOrCascade<Value>(to promise: EventLoopPromise<Value>?)
where Wrapped == EventLoopPromise<Value> {
guard let promise = promise else { return }
switch self {
-1
View File
@@ -31,4 +31,3 @@ public protocol FileDescriptor {
/// Close this `FileDescriptor`.
func close() throws
}
+14 -11
View File
@@ -51,7 +51,10 @@ public final class NIOFileHandle: FileDescriptor {
}
deinit {
assert(!self.isOpen, "leaked open NIOFileHandle(descriptor: \(self.descriptor)). Call `close()` to close or `takeDescriptorOwnership()` to take ownership and close by some other means.")
assert(
!self.isOpen,
"leaked open NIOFileHandle(descriptor: \(self.descriptor)). Call `close()` to close or `takeDescriptorOwnership()` to take ownership and close by some other means."
)
}
/// Duplicates this `NIOFileHandle`. This means that a new `NIOFileHandle` object with a new underlying file descriptor
@@ -61,7 +64,7 @@ public final class NIOFileHandle: FileDescriptor {
///
/// - returns: A new `NIOFileHandle` with a fresh underlying file descriptor but shared seek pointer.
public func duplicate() throws -> NIOFileHandle {
return try withUnsafeFileDescriptor { fd in
try withUnsafeFileDescriptor { fd in
NIOFileHandle(descriptor: try SystemCalls.dup(descriptor: fd))
}
}
@@ -132,18 +135,18 @@ extension NIOFileHandle {
public static let `default` = Flags(posixMode: 0, posixFlags: 0)
#if os(Windows)
#if os(Windows)
public static let defaultPermissions = _S_IREAD | _S_IWRITE
#else
#else
public static let defaultPermissions = S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH
#endif
#endif
/// Allows file creation when opening file for writing. File owner is set to the effective user ID of the process.
///
/// - parameters:
/// - posixMode: `file mode` applied when file is created. Default permissions are: read and write for fileowner, read for owners group and others.
public static func allowFileCreation(posixMode: NIOPOSIXFileMode = defaultPermissions) -> Flags {
return Flags(posixMode: posixMode, posixFlags: O_CREAT)
Flags(posixMode: posixMode, posixFlags: O_CREAT)
}
/// Allows the specification of POSIX flags (e.g. `O_TRUNC`) and mode (e.g. `S_IWUSR`)
@@ -153,7 +156,7 @@ extension NIOFileHandle {
/// - mode: The POSIX mode (the third parameter for `open(2)`).
/// - returns: A `NIOFileHandle.Mode` equivalent to the given POSIX flags and mode.
public static func posix(flags: CInt, mode: NIOPOSIXFileMode) -> Flags {
return Flags(posixMode: mode, posixFlags: flags)
Flags(posixMode: mode, posixFlags: flags)
}
}
@@ -164,11 +167,11 @@ extension NIOFileHandle {
/// - mode: Access mode. Default mode is `.read`.
/// - flags: Additional POSIX flags.
public convenience init(path: String, mode: Mode = .read, flags: Flags = .default) throws {
#if os(Windows)
#if os(Windows)
let fl = mode.posixFlags | flags.posixFlags | _O_NOINHERIT
#else
#else
let fl = mode.posixFlags | flags.posixFlags | O_CLOEXEC
#endif
#endif
let fd = try SystemCalls.open(file: path, oFlag: fl, mode: flags.posixMode)
self.init(descriptor: fd)
}
@@ -186,6 +189,6 @@ extension NIOFileHandle {
extension NIOFileHandle: CustomStringConvertible {
public var description: String {
return "FileHandle { descriptor: \(self.descriptor) }"
"FileHandle { descriptor: \(self.descriptor) }"
}
}
+6 -7
View File
@@ -23,7 +23,6 @@ import Musl
#error("The File Region module was unable to identify your C library.")
#endif
/// A `FileRegion` represent a readable portion usually created to be sent over the network.
///
/// Usually a `FileRegion` will allow the underlying transport to use `sendfile` to transfer its content and so allows transferring
@@ -47,7 +46,7 @@ public struct FileRegion {
/// The current reader index of this `FileRegion`
private(set) public var readerIndex: Int {
get {
return Int(self._readerIndex)
Int(self._readerIndex)
}
set {
self._readerIndex = _UInt56(newValue)
@@ -56,7 +55,7 @@ public struct FileRegion {
/// The end index of this `FileRegion`.
public var endIndex: Int {
return Int(self._endIndex)
Int(self._endIndex)
}
/// Create a new `FileRegion` from an open `NIOFileHandle`.
@@ -75,7 +74,7 @@ public struct FileRegion {
/// The number of readable bytes within this FileRegion (taking the `readerIndex` and `endIndex` into account).
public var readableBytes: Int {
return endIndex - readerIndex
endIndex - readerIndex
}
/// Move the readerIndex forward by `offset`.
@@ -106,13 +105,13 @@ extension FileRegion {
}
extension FileRegion: Equatable {
public static func ==(lhs: FileRegion, rhs: FileRegion) -> Bool {
return lhs.fileHandle === rhs.fileHandle && lhs.readerIndex == rhs.readerIndex && lhs.endIndex == rhs.endIndex
public static func == (lhs: FileRegion, rhs: FileRegion) -> Bool {
lhs.fileHandle === rhs.fileHandle && lhs.readerIndex == rhs.readerIndex && lhs.endIndex == rhs.endIndex
}
}
extension FileRegion: CustomStringConvertible {
public var description: String {
return "FileRegion { handle: \(self.fileHandle), readerIndex: \(self.readerIndex), endIndex: \(self.endIndex) }"
"FileRegion { handle: \(self.fileHandle), readerIndex: \(self.readerIndex), endIndex: \(self.endIndex) }"
}
}
+49 -30
View File
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
import Atomics
#if canImport(Darwin)
import Darwin
#elseif os(Windows)
@@ -49,8 +50,10 @@ extension NIOSingletons {
}
get {
return Self.getTrustworthyThreadCount(rawStorage: globalRawSuggestedLoopCount,
environmentVariable: "NIO_SINGLETON_GROUP_LOOP_COUNT")
Self.getTrustworthyThreadCount(
rawStorage: globalRawSuggestedLoopCount,
environmentVariable: "NIO_SINGLETON_GROUP_LOOP_COUNT"
)
}
}
@@ -67,8 +70,10 @@ extension NIOSingletons {
}
get {
return Self.getTrustworthyThreadCount(rawStorage: globalRawSuggestedBlockingThreadCount,
environmentVariable: "NIO_SINGLETON_BLOCKING_POOL_THREAD_COUNT")
Self.getTrustworthyThreadCount(
rawStorage: globalRawSuggestedBlockingThreadCount,
environmentVariable: "NIO_SINGLETON_BLOCKING_POOL_THREAD_COUNT"
)
}
}
@@ -79,9 +84,11 @@ extension NIOSingletons {
/// - note: This value must be set _before_ any singletons are used and must only be set once.
public static var singletonsEnabledSuggestion: Bool {
get {
let (exchanged, original) = globalRawSingletonsEnabled.compareExchange(expected: 0,
desired: 1,
ordering: .relaxed)
let (exchanged, original) = globalRawSingletonsEnabled.compareExchange(
expected: 0,
desired: 1,
ordering: .relaxed
)
if exchanged {
// Never been set, we're committing to the default (enabled).
assert(original == 0)
@@ -96,15 +103,19 @@ extension NIOSingletons {
set {
let intRepresentation = newValue ? 1 : -1
let (exchanged, _) = globalRawSingletonsEnabled.compareExchange(expected: 0,
desired: intRepresentation,
ordering: .relaxed)
let (exchanged, _) = globalRawSingletonsEnabled.compareExchange(
expected: 0,
desired: intRepresentation,
ordering: .relaxed
)
guard exchanged else {
fatalError("""
Bug in user code: Global singleton enabled suggestion has been changed after \
user or has been changed more than once. Either is an error, you must set this value very \
early and only once.
""")
fatalError(
"""
Bug in user code: Global singleton enabled suggestion has been changed after \
user or has been changed more than once. Either is an error, you must set this value very \
early and only once.
"""
)
}
}
}
@@ -124,19 +135,25 @@ extension NIOSingletons {
// to 5.
let (exchanged, _) = rawStorage.compareExchange(expected: 0, desired: -userValue, ordering: .relaxed)
guard exchanged else {
fatalError("""
Bug in user code: Global singleton suggested loop/thread count has been changed after \
user or has been changed more than once. Either is an error, you must set this value very early \
and only once.
""")
fatalError(
"""
Bug in user code: Global singleton suggested loop/thread count has been changed after \
user or has been changed more than once. Either is an error, you must set this value very early \
and only once.
"""
)
}
}
private static func validateTrustedThreadCount(_ threadCount: Int) {
assert(threadCount > 0,
"BUG IN NIO, please report: negative suggested loop/thread count: \(threadCount)")
assert(threadCount <= 1024,
"BUG IN NIO, please report: overly big suggested loop/thread count: \(threadCount)")
assert(
threadCount > 0,
"BUG IN NIO, please report: negative suggested loop/thread count: \(threadCount)"
)
assert(
threadCount <= 1024,
"BUG IN NIO, please report: overly big suggested loop/thread count: \(threadCount)"
)
}
private static func getTrustworthyThreadCount(rawStorage: ManagedAtomic<Int>, environmentVariable: String) -> Int {
@@ -144,15 +161,15 @@ extension NIOSingletons {
let rawSuggestion = rawStorage.load(ordering: .relaxed)
switch rawSuggestion {
case 0: // == 0
case 0: // == 0
// Not set by user, not yet finalised, let's try to get it from the env var and fall back to
// `System.coreCount`.
let envVarString = getenv(environmentVariable).map { String(cString: $0) }
returnedValueUnchecked = envVarString.flatMap(Int.init) ?? System.coreCount
case .min ..< 0: // < 0
case .min..<0: // < 0
// Untrusted and unchecked user value. Let's invert and then sanitise/check.
returnedValueUnchecked = -rawSuggestion
case 1 ... .max: // > 0
case 1 ... .max: // > 0
// Trustworthy value that has been evaluated and sanitised before.
let returnValue = rawSuggestion
Self.validateTrustedThreadCount(returnValue)
@@ -167,9 +184,11 @@ extension NIOSingletons {
Self.validateTrustedThreadCount(returnValue)
// Store it for next time.
let (exchanged, _) = rawStorage.compareExchange(expected: rawSuggestion,
desired: returnValue,
ordering: .relaxed)
let (exchanged, _) = rawStorage.compareExchange(
expected: rawSuggestion,
desired: returnValue,
ordering: .relaxed
)
if !exchanged {
// We lost the race, this must mean it has been concurrently set correctly so we can safely recurse
// and try again.
+31 -21
View File
@@ -26,7 +26,7 @@ import typealias WinSDK.WCHAR
import typealias WinSDK.WORD
internal func MAKELANGID(_ p: WORD, _ s: WORD) -> DWORD {
return DWORD((s << 10) | p)
DWORD((s << 10) | p)
}
#elseif canImport(Glibc)
import Glibc
@@ -49,15 +49,19 @@ public struct IOError: Swift.Error {
/// The actual reason (in an human-readable form) for this `IOError`.
private var failureDescription: String
@available(*, deprecated, message: "NIO no longer uses FailureDescription, use IOError.description for a human-readable error description")
@available(
*,
deprecated,
message: "NIO no longer uses FailureDescription, use IOError.description for a human-readable error description"
)
public var reason: FailureDescription {
return .reason(self.failureDescription)
.reason(self.failureDescription)
}
private enum Error {
#if os(Windows)
case windows(DWORD)
case winsock(CInt)
case windows(DWORD)
case winsock(CInt)
#endif
case errno(CInt)
}
@@ -70,13 +74,13 @@ public struct IOError: Swift.Error {
case .errno(let code):
return code
#if os(Windows)
default:
fatalError("IOError domain is not `errno`")
default:
fatalError("IOError domain is not `errno`")
#endif
}
}
#if os(Windows)
#if os(Windows)
public init(windows code: DWORD, reason: String) {
self.error = .windows(code)
self.failureDescription = reason
@@ -86,7 +90,7 @@ public struct IOError: Swift.Error {
self.error = .winsock(code)
self.failureDescription = reason
}
#endif
#endif
/// Creates a new `IOError``
///
@@ -126,9 +130,10 @@ private func reasonForError(errnoCode: CInt, reason: String) -> String {
#if os(Windows)
private func reasonForWinError(_ code: DWORD) -> String {
let dwFlags: DWORD = DWORD(FORMAT_MESSAGE_ALLOCATE_BUFFER)
| DWORD(FORMAT_MESSAGE_FROM_SYSTEM)
| DWORD(FORMAT_MESSAGE_IGNORE_INSERTS)
let dwFlags: DWORD =
DWORD(FORMAT_MESSAGE_ALLOCATE_BUFFER)
| DWORD(FORMAT_MESSAGE_FROM_SYSTEM)
| DWORD(FORMAT_MESSAGE_IGNORE_INSERTS)
var buffer: UnsafeMutablePointer<WCHAR>?
// We use `FORMAT_MESSAGE_ALLOCATE_BUFFER` in flags which means that the
@@ -136,9 +141,15 @@ private func reasonForWinError(_ code: DWORD) -> String {
// expects a `LPWSTR` and expects the user to type-pun in this case.
let dwResult: DWORD = withUnsafeMutablePointer(to: &buffer) {
$0.withMemoryRebound(to: WCHAR.self, capacity: 2) {
FormatMessageW(dwFlags, nil, code,
MAKELANGID(WORD(LANG_NEUTRAL), WORD(SUBLANG_DEFAULT)),
$0, 0, nil)
FormatMessageW(
dwFlags,
nil,
code,
MAKELANGID(WORD(LANG_NEUTRAL), WORD(SUBLANG_DEFAULT)),
$0,
0,
nil
)
}
}
guard dwResult > 0, let message = buffer else {
@@ -151,11 +162,11 @@ private func reasonForWinError(_ code: DWORD) -> String {
extension IOError: CustomStringConvertible {
public var description: String {
return self.localizedDescription
self.localizedDescription
}
public var localizedDescription: String {
#if os(Windows)
#if os(Windows)
switch self.error {
case .errno(let errno):
return reasonForError(errnoCode: errno, reason: self.failureDescription)
@@ -164,9 +175,9 @@ extension IOError: CustomStringConvertible {
case .winsock(let code):
return reasonForWinError(DWORD(code))
}
#else
#else
return reasonForError(errnoCode: self.errnoCode, reason: self.failureDescription)
#endif
#endif
}
}
@@ -181,7 +192,7 @@ enum CoreIOResult<T: Equatable>: Equatable {
case processed(T)
}
internal extension CoreIOResult where T: FixedWidthInteger {
extension CoreIOResult where T: FixedWidthInteger {
var result: T {
switch self {
case .processed(let value):
@@ -191,4 +202,3 @@ internal extension CoreIOResult where T: FixedWidthInteger {
}
}
}
+2 -2
View File
@@ -19,7 +19,7 @@
public struct NIOIPProtocol: RawRepresentable, Hashable, Sendable {
public typealias RawValue = UInt8
public var rawValue: RawValue
@inlinable
public init(rawValue: RawValue) {
self.rawValue = rawValue
@@ -169,7 +169,7 @@ extension NIOIPProtocol: CustomStringConvertible {
default: return nil
}
}
public var description: String {
let name = self.name ?? "Unknown Protocol"
return "\(name) - \(rawValue)"
+24 -16
View File
@@ -19,11 +19,15 @@ enum _IntegerBitPacking {}
extension _IntegerBitPacking {
@inlinable
static func packUU<Left: FixedWidthInteger & UnsignedInteger,
Right: FixedWidthInteger & UnsignedInteger,
Result: FixedWidthInteger & UnsignedInteger>(_ left: Left,
_ right: Right,
type: Result.Type = Result.self) -> Result {
static func packUU<
Left: FixedWidthInteger & UnsignedInteger,
Right: FixedWidthInteger & UnsignedInteger,
Result: FixedWidthInteger & UnsignedInteger
>(
_ left: Left,
_ right: Right,
type: Result.Type = Result.self
) -> Result {
assert(MemoryLayout<Left>.size + MemoryLayout<Right>.size <= MemoryLayout<Result>.size)
let resultLeft = Result(left)
@@ -34,11 +38,15 @@ extension _IntegerBitPacking {
}
@inlinable
static func unpackUU<Input: FixedWidthInteger & UnsignedInteger,
Left: FixedWidthInteger & UnsignedInteger,
Right: FixedWidthInteger & UnsignedInteger>(_ input: Input,
leftType: Left.Type = Left.self,
rightType: Right.Type = Right.self) -> (Left, Right) {
static func unpackUU<
Input: FixedWidthInteger & UnsignedInteger,
Left: FixedWidthInteger & UnsignedInteger,
Right: FixedWidthInteger & UnsignedInteger
>(
_ input: Input,
leftType: Left.Type = Left.self,
rightType: Right.Type = Right.self
) -> (Left, Right) {
assert(MemoryLayout<Left>.size + MemoryLayout<Right>.size <= MemoryLayout<Input>.size)
let leftMask = Input(Left.max)
@@ -57,7 +65,7 @@ enum IntegerBitPacking {}
extension IntegerBitPacking {
@inlinable
static func packUInt32UInt16UInt8(_ left: UInt32, _ middle: UInt16, _ right: UInt8) -> UInt64 {
return _IntegerBitPacking.packUU(
_IntegerBitPacking.packUU(
_IntegerBitPacking.packUU(right, middle, type: UInt32.self),
left
)
@@ -72,27 +80,27 @@ extension IntegerBitPacking {
@inlinable
static func packUInt8UInt8(_ left: UInt8, _ right: UInt8) -> UInt16 {
return _IntegerBitPacking.packUU(left, right)
_IntegerBitPacking.packUU(left, right)
}
@inlinable
static func unpackUInt8UInt8(_ value: UInt16) -> (UInt8, UInt8) {
return _IntegerBitPacking.unpackUU(value)
_IntegerBitPacking.unpackUU(value)
}
@inlinable
static func packUInt16UInt8(_ left: UInt16, _ right: UInt8) -> UInt32 {
return _IntegerBitPacking.packUU(left, right)
_IntegerBitPacking.packUU(left, right)
}
@inlinable
static func unpackUInt16UInt8(_ value: UInt32) -> (UInt16, UInt8) {
return _IntegerBitPacking.unpackUU(value)
_IntegerBitPacking.unpackUU(value)
}
@inlinable
static func packUInt32CInt(_ left: UInt32, _ right: CInt) -> UInt64 {
return _IntegerBitPacking.packUU(left, UInt32(truncatingIfNeeded: right))
_IntegerBitPacking.packUU(left, UInt32(truncatingIfNeeded: right))
}
@inlinable
+12 -11
View File
@@ -50,18 +50,17 @@ extension Int {
}
}
extension _UInt24: Equatable {
@inlinable
public static func ==(lhs: _UInt24, rhs: _UInt24) -> Bool {
return lhs._backing == rhs._backing
public static func == (lhs: _UInt24, rhs: _UInt24) -> Bool {
lhs._backing == rhs._backing
}
}
extension _UInt24: CustomStringConvertible {
@usableFromInline
var description: String {
return UInt32(self).description
UInt32(self).description
}
}
@@ -77,7 +76,7 @@ struct _UInt56: Sendable {
static let bitWidth: Int = 56
private static let initializeUInt64 : UInt64 = (1 << 56) - 1
private static let initializeUInt64: UInt64 = (1 << 56) - 1
static let max: _UInt56 = .init(initializeUInt64)
static let min: _UInt56 = .init(0)
}
@@ -90,9 +89,11 @@ extension _UInt56 {
extension UInt64 {
init(_ value: _UInt56) {
self = IntegerBitPacking.packUInt32UInt16UInt8(value._backing.0,
value._backing.1,
value._backing.2)
self = IntegerBitPacking.packUInt32UInt16UInt8(
value._backing.0,
value._backing.1,
value._backing.2
)
}
}
@@ -104,13 +105,13 @@ extension Int {
extension _UInt56: Equatable {
@inlinable
public static func ==(lhs: _UInt56, rhs: _UInt56) -> Bool {
return lhs._backing == rhs._backing
public static func == (lhs: _UInt56, rhs: _UInt56) -> Bool {
lhs._backing == rhs._backing
}
}
extension _UInt56: CustomStringConvertible {
var description: String {
return UInt64(self).description
UInt64(self).description
}
}
+69 -60
View File
@@ -43,8 +43,8 @@ import typealias WinSDK.UINT8
#endif
#if !os(Windows)
private extension ifaddrs {
var dstaddr: UnsafeMutablePointer<sockaddr>? {
extension ifaddrs {
fileprivate var dstaddr: UnsafeMutablePointer<sockaddr>? {
#if os(Linux) || os(Android)
return self.ifa_ifu.ifu_dstaddr
#elseif canImport(Darwin)
@@ -52,7 +52,7 @@ private extension ifaddrs {
#endif
}
var broadaddr: UnsafeMutablePointer<sockaddr>? {
fileprivate var broadaddr: UnsafeMutablePointer<sockaddr>? {
#if os(Linux) || os(Android)
return self.ifa_ifu.ifu_broadaddr
#elseif canImport(Darwin)
@@ -93,11 +93,15 @@ public final class NIONetworkInterface: Sendable {
/// The index of the interface, as provided by `if_nametoindex`.
public let interfaceIndex: Int
#if os(Windows)
internal init?(_ pAdapter: UnsafeMutablePointer<IP_ADAPTER_ADDRESSES>,
_ pAddress: UnsafeMutablePointer<IP_ADAPTER_UNICAST_ADDRESS>) {
self.name = String(decodingCString: pAdapter.pointee.FriendlyName,
as: UTF16.self)
#if os(Windows)
internal init?(
_ pAdapter: UnsafeMutablePointer<IP_ADAPTER_ADDRESSES>,
_ pAddress: UnsafeMutablePointer<IP_ADAPTER_UNICAST_ADDRESS>
) {
self.name = String(
decodingCString: pAdapter.pointee.FriendlyName,
as: UTF16.self
)
guard let address = pAddress.pointee.Address.lpSockaddr.convert() else {
return nil
}
@@ -121,7 +125,7 @@ public final class NIONetworkInterface: Sendable {
self.pointToPointDestinationAddress = nil
self.multicastSupported = false
}
#else
#else
internal init?(_ caddr: ifaddrs) {
self.name = String(cString: caddr.ifa_name!)
@@ -163,7 +167,7 @@ public final class NIONetworkInterface: Sendable {
return nil
}
}
#endif
#endif
}
@available(*, deprecated, renamed: "NIONetworkDevice")
@@ -177,13 +181,11 @@ extension NIONetworkInterface: CustomDebugStringConvertible {
@available(*, deprecated, renamed: "NIONetworkDevice")
extension NIONetworkInterface: Equatable {
public static func ==(lhs: NIONetworkInterface, rhs: NIONetworkInterface) -> Bool {
return lhs.name == rhs.name &&
lhs.address == rhs.address &&
lhs.netmask == rhs.netmask &&
lhs.broadcastAddress == rhs.broadcastAddress &&
lhs.pointToPointDestinationAddress == rhs.pointToPointDestinationAddress &&
lhs.interfaceIndex == rhs.interfaceIndex
public static func == (lhs: NIONetworkInterface, rhs: NIONetworkInterface) -> Bool {
lhs.name == rhs.name && lhs.address == rhs.address && lhs.netmask == rhs.netmask
&& lhs.broadcastAddress == rhs.broadcastAddress
&& lhs.pointToPointDestinationAddress == rhs.pointToPointDestinationAddress
&& lhs.interfaceIndex == rhs.interfaceIndex
}
}
@@ -212,7 +214,7 @@ public struct NIONetworkDevice {
/// The name of the network device.
public var name: String {
get {
return self.backing.name
self.backing.name
}
set {
self.uniquifyIfNeeded()
@@ -223,7 +225,7 @@ public struct NIONetworkDevice {
/// The address associated with the given network device.
public var address: SocketAddress? {
get {
return self.backing.address
self.backing.address
}
set {
self.uniquifyIfNeeded()
@@ -234,7 +236,7 @@ public struct NIONetworkDevice {
/// The netmask associated with this address, if any.
public var netmask: SocketAddress? {
get {
return self.backing.netmask
self.backing.netmask
}
set {
self.uniquifyIfNeeded()
@@ -246,7 +248,7 @@ public struct NIONetworkDevice {
/// interfaces do not, especially those that have a `pointToPointDestinationAddress`.
public var broadcastAddress: SocketAddress? {
get {
return self.backing.broadcastAddress
self.backing.broadcastAddress
}
set {
self.uniquifyIfNeeded()
@@ -259,7 +261,7 @@ public struct NIONetworkDevice {
/// instead.
public var pointToPointDestinationAddress: SocketAddress? {
get {
return self.backing.pointToPointDestinationAddress
self.backing.pointToPointDestinationAddress
}
set {
self.uniquifyIfNeeded()
@@ -270,7 +272,7 @@ public struct NIONetworkDevice {
/// If the Interface supports Multicast
public var multicastSupported: Bool {
get {
return self.backing.multicastSupported
self.backing.multicastSupported
}
set {
self.uniquifyIfNeeded()
@@ -281,7 +283,7 @@ public struct NIONetworkDevice {
/// The index of the interface, as provided by `if_nametoindex`.
public var interfaceIndex: Int {
get {
return self.backing.interfaceIndex
self.backing.interfaceIndex
}
set {
self.uniquifyIfNeeded()
@@ -294,15 +296,17 @@ public struct NIONetworkDevice {
/// This constructor will fail if NIO does not understand the format of the underlying
/// socket address family. This is quite common: for example, Linux will return AF_PACKET
/// addressed interfaces on most platforms, which NIO does not currently understand.
#if os(Windows)
internal init?(_ pAdapter: UnsafeMutablePointer<IP_ADAPTER_ADDRESSES>,
_ pAddress: UnsafeMutablePointer<IP_ADAPTER_UNICAST_ADDRESS>) {
#if os(Windows)
internal init?(
_ pAdapter: UnsafeMutablePointer<IP_ADAPTER_ADDRESSES>,
_ pAddress: UnsafeMutablePointer<IP_ADAPTER_UNICAST_ADDRESS>
) {
guard let backing = Backing(pAdapter, pAddress) else {
return nil
}
self.backing = backing
}
#else
#else
internal init?(_ caddr: ifaddrs) {
guard let backing = Backing(caddr) else {
return nil
@@ -310,9 +314,9 @@ public struct NIONetworkDevice {
self.backing = backing
}
#endif
#endif
#if !os(Windows)
#if !os(Windows)
/// Convert a `NIONetworkInterface` to a `NIONetworkDevice`. As `NIONetworkDevice`s are a superset of `NIONetworkInterface`s,
/// it is always possible to perform this conversion.
@available(*, deprecated, message: "This is a compatibility helper, and will be removed in a future release")
@@ -327,15 +331,17 @@ public struct NIONetworkDevice {
interfaceIndex: interface.interfaceIndex
)
}
#endif
#endif
public init(name: String,
address: SocketAddress?,
netmask: SocketAddress?,
broadcastAddress: SocketAddress?,
pointToPointDestinationAddress: SocketAddress,
multicastSupported: Bool,
interfaceIndex: Int) {
public init(
name: String,
address: SocketAddress?,
netmask: SocketAddress?,
broadcastAddress: SocketAddress?,
pointToPointDestinationAddress: SocketAddress,
multicastSupported: Bool,
interfaceIndex: Int
) {
self.backing = Backing(
name: name,
address: address,
@@ -387,11 +393,15 @@ extension NIONetworkDevice {
/// This constructor will fail if NIO does not understand the format of the underlying
/// socket address family. This is quite common: for example, Linux will return AF_PACKET
/// addressed interfaces on most platforms, which NIO does not currently understand.
#if os(Windows)
internal init?(_ pAdapter: UnsafeMutablePointer<IP_ADAPTER_ADDRESSES>,
_ pAddress: UnsafeMutablePointer<IP_ADAPTER_UNICAST_ADDRESS>) {
self.name = String(decodingCString: pAdapter.pointee.FriendlyName,
as: UTF16.self)
#if os(Windows)
internal init?(
_ pAdapter: UnsafeMutablePointer<IP_ADAPTER_ADDRESSES>,
_ pAddress: UnsafeMutablePointer<IP_ADAPTER_UNICAST_ADDRESS>
) {
self.name = String(
decodingCString: pAdapter.pointee.FriendlyName,
as: UTF16.self
)
self.address = pAddress.pointee.Address.lpSockaddr.convert()
switch pAddress.pointee.Address.lpSockaddr.pointee.sa_family {
@@ -412,7 +422,7 @@ extension NIONetworkDevice {
self.pointToPointDestinationAddress = nil
self.multicastSupported = false
}
#else
#else
internal init?(_ caddr: ifaddrs) {
self.name = String(cString: caddr.ifa_name!)
self.address = caddr.ifa_addr.flatMap { $0.convert() }
@@ -436,7 +446,7 @@ extension NIONetworkDevice {
return nil
}
}
#endif
#endif
init(copying original: Backing) {
self.name = original.name
@@ -448,13 +458,15 @@ extension NIONetworkDevice {
self.interfaceIndex = original.interfaceIndex
}
init(name: String,
address: SocketAddress?,
netmask: SocketAddress?,
broadcastAddress: SocketAddress?,
pointToPointDestinationAddress: SocketAddress?,
multicastSupported: Bool,
interfaceIndex: Int) {
init(
name: String,
address: SocketAddress?,
netmask: SocketAddress?,
broadcastAddress: SocketAddress?,
pointToPointDestinationAddress: SocketAddress?,
multicastSupported: Bool,
interfaceIndex: Int
) {
self.name = name
self.address = address
self.netmask = netmask
@@ -476,13 +488,11 @@ extension NIONetworkDevice: CustomDebugStringConvertible {
// Sadly, as this is class-backed we cannot synthesise the implementation.
extension NIONetworkDevice: Equatable {
public static func ==(lhs: NIONetworkDevice, rhs: NIONetworkDevice) -> Bool {
return lhs.name == rhs.name &&
lhs.address == rhs.address &&
lhs.netmask == rhs.netmask &&
lhs.broadcastAddress == rhs.broadcastAddress &&
lhs.pointToPointDestinationAddress == rhs.pointToPointDestinationAddress &&
lhs.interfaceIndex == rhs.interfaceIndex
public static func == (lhs: NIONetworkDevice, rhs: NIONetworkDevice) -> Bool {
lhs.name == rhs.name && lhs.address == rhs.address && lhs.netmask == rhs.netmask
&& lhs.broadcastAddress == rhs.broadcastAddress
&& lhs.pointToPointDestinationAddress == rhs.pointToPointDestinationAddress
&& lhs.interfaceIndex == rhs.interfaceIndex
}
}
@@ -496,4 +506,3 @@ extension NIONetworkDevice: Hashable {
hasher.combine(self.interfaceIndex)
}
}
+10 -8
View File
@@ -30,7 +30,7 @@ enum Linux {
var buf = ByteBufferAllocator().buffer(capacity: 1024)
try buf.writeWithUnsafeMutableBytes(minimumWritableBytes: buf.capacity) { ptr in
let res = try fh.withUnsafeFileDescriptor { fd -> CoreIOResult<ssize_t> in
return try SystemCalls.read(descriptor: fd, pointer: ptr.baseAddress!, size: ptr.count)
try SystemCalls.read(descriptor: fd, pointer: ptr.baseAddress!, size: ptr.count)
}
switch res {
case .processed(let n):
@@ -62,8 +62,10 @@ enum Linux {
/// Get the available core count according to cgroup1 restrictions.
/// Round up to the next whole number.
static func coreCountCgroup1Restriction(quota quotaPath: String = Linux.cfsQuotaPath,
period periodPath: String = Linux.cfsPeriodPath) -> Int? {
static func coreCountCgroup1Restriction(
quota quotaPath: String = Linux.cfsQuotaPath,
period periodPath: String = Linux.cfsPeriodPath
) -> Int? {
guard
let quota = try? Int(firstLineOfFile(path: quotaPath)),
quota > 0
@@ -72,18 +74,18 @@ enum Linux {
let period = try? Int(firstLineOfFile(path: periodPath)),
period > 0
else { return nil }
return (quota - 1 + period) / period // always round up if fractional CPU quota requested
return (quota - 1 + period) / period // always round up if fractional CPU quota requested
}
/// Get the available core count according to cgroup2 restrictions.
/// Round up to the next whole number.
static func coreCountCgroup2Restriction(cpuMaxPath: String = Linux.cfsCpuMaxPath) -> Int? {
guard let maxDetails = try? firstLineOfFile(path: cpuMaxPath),
let spaceIndex = maxDetails.firstIndex(of: " "),
let quota = Int(maxDetails[maxDetails.startIndex ..< spaceIndex]),
let period = Int(maxDetails[maxDetails.index(after: spaceIndex) ..< maxDetails.endIndex])
let spaceIndex = maxDetails.firstIndex(of: " "),
let quota = Int(maxDetails[maxDetails.startIndex..<spaceIndex]),
let period = Int(maxDetails[maxDetails.index(after: spaceIndex)..<maxDetails.endIndex])
else { return nil }
return (quota - 1 + period) / period // always round up if fractional CPU quota requested
return (quota - 1 + period) / period // always round up if fractional CPU quota requested
}
}
#endif
+15 -15
View File
@@ -19,7 +19,7 @@
/// safe to write.
public struct MarkedCircularBuffer<Element>: CustomStringConvertible {
@usableFromInline internal var _buffer: CircularBuffer<Element>
@usableFromInline internal var _markedIndexOffset: Int? /* nil: nothing marked */
@usableFromInline internal var _markedIndexOffset: Int? // nil: nothing marked
/// Create a new instance.
///
@@ -60,24 +60,24 @@ public struct MarkedCircularBuffer<Element>: CustomStringConvertible {
/// The first element in the buffer.
@inlinable
public var first: Element? {
return self._buffer.first
self._buffer.first
}
/// If the buffer is empty.
@inlinable
public var isEmpty: Bool {
return self._buffer.isEmpty
self._buffer.isEmpty
}
/// The number of elements in the buffer.
@inlinable
public var count: Int {
return self._buffer.count
self._buffer.count
}
@inlinable
public var description: String {
return self._buffer.description
self._buffer.description
}
// MARK: Marking
@@ -119,13 +119,13 @@ public struct MarkedCircularBuffer<Element>: CustomStringConvertible {
/// Returns the marked element.
@inlinable
public var markedElement: Element? {
return self.markedElementIndex.map { self._buffer[$0] }
self.markedElementIndex.map { self._buffer[$0] }
}
/// Returns true if the buffer has been marked at all.
@inlinable
public var hasMark: Bool {
return self._markedIndexOffset != nil
self._markedIndexOffset != nil
}
}
@@ -136,20 +136,20 @@ extension MarkedCircularBuffer: Collection, MutableCollection {
@inlinable
public func index(after i: Index) -> Index {
return self._buffer.index(after: i)
self._buffer.index(after: i)
}
@inlinable
public var startIndex: Index { return self._buffer.startIndex }
public var startIndex: Index { self._buffer.startIndex }
@inlinable
public var endIndex: Index { return self._buffer.endIndex }
public var endIndex: Index { self._buffer.endIndex }
/// Retrieves the element at the given index from the buffer, without removing it.
@inlinable
public subscript(index: Index) -> Element {
get {
return self._buffer[index]
self._buffer[index]
}
set {
self._buffer[index] = newValue
@@ -159,7 +159,7 @@ extension MarkedCircularBuffer: Collection, MutableCollection {
@inlinable
public subscript(bounds: Range<Index>) -> SubSequence {
get {
return self._buffer[bounds]
self._buffer[bounds]
}
set {
var index = bounds.lowerBound
@@ -176,17 +176,17 @@ extension MarkedCircularBuffer: Collection, MutableCollection {
extension MarkedCircularBuffer: RandomAccessCollection {
@inlinable
public func index(_ i: Index, offsetBy distance: Int) -> Index {
return self._buffer.index(i, offsetBy: distance)
self._buffer.index(i, offsetBy: distance)
}
@inlinable
public func distance(from start: Index, to end: Index) -> Int {
return self._buffer.distance(from: start, to: end)
self._buffer.distance(from: start, to: end)
}
@inlinable
public func index(before i: Index) -> Index {
return self._buffer.index(before: i)
self._buffer.index(before: i)
}
}
+8 -10
View File
@@ -25,7 +25,7 @@ public protocol MulticastChannel: Channel {
/// `nil` if you are not interested in the result of the operation.
func joinGroup(_ group: SocketAddress, promise: EventLoopPromise<Void>?)
#if !os(Windows)
#if !os(Windows)
/// Request that the `MulticastChannel` join the multicast group given by `group` on the interface
/// given by `interface`.
///
@@ -36,7 +36,7 @@ public protocol MulticastChannel: Channel {
/// `nil` if you are not interested in the result of the operation.
@available(*, deprecated, renamed: "joinGroup(_:device:promise:)")
func joinGroup(_ group: SocketAddress, interface: NIONetworkInterface?, promise: EventLoopPromise<Void>?)
#endif
#endif
/// Request that the `MulticastChannel` join the multicast group given by `group` on the device
/// given by `device`.
@@ -56,7 +56,7 @@ public protocol MulticastChannel: Channel {
/// `nil` if you are not interested in the result of the operation.
func leaveGroup(_ group: SocketAddress, promise: EventLoopPromise<Void>?)
#if !os(Windows)
#if !os(Windows)
/// Request that the `MulticastChannel` leave the multicast group given by `group` on the interface
/// given by `interface`.
///
@@ -67,7 +67,7 @@ public protocol MulticastChannel: Channel {
/// `nil` if you are not interested in the result of the operation.
@available(*, deprecated, renamed: "leaveGroup(_:device:promise:)")
func leaveGroup(_ group: SocketAddress, interface: NIONetworkInterface?, promise: EventLoopPromise<Void>?)
#endif
#endif
/// Request that the `MulticastChannel` leave the multicast group given by `group` on the device
/// given by `device`.
@@ -80,7 +80,6 @@ public protocol MulticastChannel: Channel {
func leaveGroup(_ group: SocketAddress, device: NIONetworkDevice?, promise: EventLoopPromise<Void>?)
}
// MARK:- Default implementations for MulticastChannel
extension MulticastChannel {
public func joinGroup(_ group: SocketAddress, promise: EventLoopPromise<Void>?) {
@@ -93,14 +92,14 @@ extension MulticastChannel {
return promise.futureResult
}
#if !os(Windows)
#if !os(Windows)
@available(*, deprecated, renamed: "joinGroup(_:device:)")
public func joinGroup(_ group: SocketAddress, interface: NIONetworkInterface?) -> EventLoopFuture<Void> {
let promise = self.eventLoop.makePromise(of: Void.self)
self.joinGroup(group, interface: interface, promise: promise)
return promise.futureResult
}
#endif
#endif
public func joinGroup(_ group: SocketAddress, device: NIONetworkDevice?) -> EventLoopFuture<Void> {
let promise = self.eventLoop.makePromise(of: Void.self)
@@ -118,14 +117,14 @@ extension MulticastChannel {
return promise.futureResult
}
#if !os(Windows)
#if !os(Windows)
@available(*, deprecated, renamed: "leaveGroup(_:device:)")
public func leaveGroup(_ group: SocketAddress, interface: NIONetworkInterface?) -> EventLoopFuture<Void> {
let promise = self.eventLoop.makePromise(of: Void.self)
self.leaveGroup(group, interface: interface, promise: promise)
return promise.futureResult
}
#endif
#endif
public func leaveGroup(_ group: SocketAddress, device: NIONetworkDevice?) -> EventLoopFuture<Void> {
let promise = self.eventLoop.makePromise(of: Void.self)
@@ -176,4 +175,3 @@ public struct NIOMulticastNotSupportedError: Error {
public struct NIOMulticastNotImplementedError: Error {
public init() {}
}
+17 -7
View File
@@ -44,7 +44,7 @@
/// }
public struct NIOAny {
@usableFromInline
/* private but _versioned */ let _storage: _NIOAny
let _storage: _NIOAny
/// Wrap a value in a `NIOAny`. In most cases you should not create a `NIOAny` directly using this constructor.
/// The abstraction that accepts values of type `NIOAny` must also provide a mechanism to do the wrapping. An
@@ -98,7 +98,9 @@ public struct NIOAny {
if let v = tryAsByteBuffer() {
return v
} else {
fatalError("tried to decode as type \(ByteBuffer.self) but found \(Mirror(reflecting: Mirror(reflecting: self._storage).children.first!.value).subjectType) with contents \(self._storage)")
fatalError(
"tried to decode as type \(ByteBuffer.self) but found \(Mirror(reflecting: Mirror(reflecting: self._storage).children.first!.value).subjectType) with contents \(self._storage)"
)
}
}
@@ -122,7 +124,9 @@ public struct NIOAny {
if let v = tryAsIOData() {
return v
} else {
fatalError("tried to decode as type \(IOData.self) but found \(Mirror(reflecting: Mirror(reflecting: self._storage).children.first!.value).subjectType) with contents \(self._storage)")
fatalError(
"tried to decode as type \(IOData.self) but found \(Mirror(reflecting: Mirror(reflecting: self._storage).children.first!.value).subjectType) with contents \(self._storage)"
)
}
}
@@ -146,7 +150,9 @@ public struct NIOAny {
if let v = tryAsFileRegion() {
return v
} else {
fatalError("tried to decode as type \(FileRegion.self) but found \(Mirror(reflecting: Mirror(reflecting: self._storage).children.first!.value).subjectType) with contents \(self._storage)")
fatalError(
"tried to decode as type \(FileRegion.self) but found \(Mirror(reflecting: Mirror(reflecting: self._storage).children.first!.value).subjectType) with contents \(self._storage)"
)
}
}
@@ -170,7 +176,9 @@ public struct NIOAny {
if let e = tryAsByteEnvelope() {
return e
} else {
fatalError("tried to decode as type \(AddressedEnvelope<ByteBuffer>.self) but found \(Mirror(reflecting: Mirror(reflecting: self._storage).children.first!.value).subjectType) with contents \(self._storage)")
fatalError(
"tried to decode as type \(AddressedEnvelope<ByteBuffer>.self) but found \(Mirror(reflecting: Mirror(reflecting: self._storage).children.first!.value).subjectType) with contents \(self._storage)"
)
}
}
@@ -197,7 +205,9 @@ public struct NIOAny {
if let v = tryAsOther(type: type) {
return v
} else {
fatalError("tried to decode as type \(T.self) but found \(Mirror(reflecting: Mirror(reflecting: self._storage).children.first!.value).subjectType) with contents \(self._storage)")
fatalError(
"tried to decode as type \(T.self) but found \(Mirror(reflecting: Mirror(reflecting: self._storage).children.first!.value).subjectType) with contents \(self._storage)"
)
}
}
@@ -262,6 +272,6 @@ extension NIOAny: Sendable {}
extension NIOAny: CustomStringConvertible {
public var description: String {
return "NIOAny { \(self.asAny()) }"
"NIOAny { \(self.asAny()) }"
}
}
+2 -3
View File
@@ -12,15 +12,14 @@
//
//===----------------------------------------------------------------------===//
/// A `ChannelInboundHandler` that closes the channel when an error is caught
public final class NIOCloseOnErrorHandler: ChannelInboundHandler, Sendable {
public typealias InboundIn = NIOAny
/// Initialize a `NIOCloseOnErrorHandler`
public init() {}
public func errorCaught(context: ChannelHandlerContext, error: Error) {
context.fireErrorCaught(error)
context.close(promise: nil)
+5 -6
View File
@@ -28,7 +28,7 @@ public struct NIOLoopBound<Value>: @unchecked Sendable {
public let _eventLoop: EventLoop
@usableFromInline
/* private */ var _value: Value
var _value: Value
/// Initialise a ``NIOLoopBound`` to `value` with the precondition that the code is running on `eventLoop`.
@inlinable
@@ -75,7 +75,7 @@ public final class NIOLoopBoundBox<Value>: @unchecked Sendable {
public let _eventLoop: EventLoop
@usableFromInline
/* private */var _value: Value
var _value: Value
@inlinable
internal init(_value value: Value, uncheckedEventLoop eventLoop: EventLoop) {
@@ -96,7 +96,7 @@ public final class NIOLoopBoundBox<Value>: @unchecked Sendable {
public static func makeEmptyBox<NonOptionalValue>(
valueType: NonOptionalValue.Type = NonOptionalValue.self,
eventLoop: EventLoop
) -> NIOLoopBoundBox<Value> where Optional<NonOptionalValue> == Value {
) -> NIOLoopBoundBox<Value> where NonOptionalValue? == Value {
// Here, we -- possibly surprisingly -- do not precondition being on the EventLoop. This is okay for a few
// reasons:
// - We write the `Optional.none` value which we know is _not_ a value of the potentially non-Sendable type
@@ -104,7 +104,7 @@ public final class NIOLoopBoundBox<Value>: @unchecked Sendable {
// - Because of Swift's Definitive Initialisation (DI), we know that we did write `self._value` before `init`
// returns.
// - The only way to ever write (or read indeed) `self._value` is by proving to be inside the `EventLoop`.
return .init(_value: nil, uncheckedEventLoop: eventLoop)
.init(_value: nil, uncheckedEventLoop: eventLoop)
}
/// Initialise a ``NIOLoopBoundBox`` by sending a `Sendable` value, validly callable off `eventLoop`.
@@ -124,7 +124,7 @@ public final class NIOLoopBoundBox<Value>: @unchecked Sendable {
// - Because of Swift's Definitive Initialisation (DI), we know that we did write `self._value` before `init`
// returns.
// - The only way to ever write (or read indeed) `self._value` is by proving to be inside the `EventLoop`.
return .init(_value: value, uncheckedEventLoop: eventLoop)
.init(_value: value, uncheckedEventLoop: eventLoop)
}
/// Access the `value` with the precondition that the code is running on `eventLoop`.
@@ -142,4 +142,3 @@ public final class NIOLoopBoundBox<Value>: @unchecked Sendable {
}
}
}
+2 -3
View File
@@ -27,7 +27,7 @@ public typealias NIOPreconcurrencySendable = _NIOPreconcurrencySendable
struct UnsafeTransfer<Wrapped> {
@usableFromInline
var wrappedValue: Wrapped
@inlinable
init(_ wrappedValue: Wrapped) {
self.wrappedValue = wrappedValue
@@ -46,7 +46,7 @@ extension UnsafeTransfer: Hashable where Wrapped: Hashable {}
final class UnsafeMutableTransferBox<Wrapped> {
@usableFromInline
var wrappedValue: Wrapped
@inlinable
init(_ wrappedValue: Wrapped) {
self.wrappedValue = wrappedValue
@@ -54,4 +54,3 @@ final class UnsafeMutableTransferBox<Wrapped> {
}
extension UnsafeMutableTransferBox: @unchecked Sendable {}
@@ -31,7 +31,7 @@ public protocol RecvByteBufferAllocator: _NIOPreconcurrencySendable {
extension RecvByteBufferAllocator {
// Default implementation to maintain API compatability.
public func nextBufferSize() -> Int? {
return nil
nil
}
}
@@ -46,17 +46,17 @@ public struct FixedSizeRecvByteBufferAllocator: RecvByteBufferAllocator {
public mutating func record(actualReadBytes: Int) -> Bool {
// Returns false as we always allocate the same size of buffers.
return false
false
}
public func buffer(allocator: ByteBufferAllocator) -> ByteBuffer {
return allocator.buffer(capacity: self.capacity)
allocator.buffer(capacity: self.capacity)
}
}
extension FixedSizeRecvByteBufferAllocator {
public func nextBufferSize() -> Int? {
return self.capacity
self.capacity
}
}
@@ -91,7 +91,7 @@ public struct AdaptiveRecvByteBufferAllocator: RecvByteBufferAllocator {
}
public func buffer(allocator: ByteBufferAllocator) -> ByteBuffer {
return allocator.buffer(capacity: self.nextReceiveBufferSize)
allocator.buffer(capacity: self.nextReceiveBufferSize)
}
public mutating func record(actualReadBytes: Int) -> Bool {
@@ -116,8 +116,9 @@ public struct AdaptiveRecvByteBufferAllocator: RecvByteBufferAllocator {
} else {
self.decreaseNow = true
}
} else if actualReadBytes >= self.nextReceiveBufferSize && upperBound <= self.maximum &&
self.nextReceiveBufferSize != upperBound {
} else if actualReadBytes >= self.nextReceiveBufferSize && upperBound <= self.maximum
&& self.nextReceiveBufferSize != upperBound
{
self.nextReceiveBufferSize = upperBound
self.decreaseNow = false
mayGrow = true
@@ -131,6 +132,6 @@ public struct AdaptiveRecvByteBufferAllocator: RecvByteBufferAllocator {
extension AdaptiveRecvByteBufferAllocator {
public func nextBufferSize() -> Int? {
return self.nextReceiveBufferSize
self.nextReceiveBufferSize
}
}
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
/// A simplified version of `ByteToMessageDecoder` that can generate zero or one messages for each invocation of `decode` or `decodeLast`.
/// Having `decode` and `decodeLast` return an optional message avoids re-entrancy problems, since the functions relinquish exclusive access
/// to the `ByteBuffer` when returning. This allows for greatly simplified processing.
@@ -51,7 +50,6 @@ public protocol NIOSingleStepByteToMessageDecoder: ByteToMessageDecoder {
mutating func decodeLast(buffer: inout ByteBuffer, seenEOF: Bool) throws -> InboundOut?
}
// MARK: NIOSingleStepByteToMessageDecoder: ByteToMessageDecoder
extension NIOSingleStepByteToMessageDecoder {
public mutating func decode(context: ChannelHandlerContext, buffer: inout ByteBuffer) throws -> DecodingState {
@@ -63,7 +61,11 @@ extension NIOSingleStepByteToMessageDecoder {
}
}
public mutating func decodeLast(context: ChannelHandlerContext, buffer: inout ByteBuffer, seenEOF: Bool) throws -> DecodingState {
public mutating func decodeLast(
context: ChannelHandlerContext,
buffer: inout ByteBuffer,
seenEOF: Bool
) throws -> DecodingState {
if let message = try self.decodeLast(buffer: &buffer, seenEOF: seenEOF) {
context.fireChannelRead(Self.wrapInboundOut(message))
return .continue
@@ -73,7 +75,6 @@ extension NIOSingleStepByteToMessageDecoder {
}
}
/// `NIOSingleStepByteToMessageProcessor` uses a `NIOSingleStepByteToMessageDecoder` to produce messages
/// from a stream of incoming bytes. It works like `ByteToMessageHandler` but may be used outside of the channel pipeline. This allows
/// processing of wrapped protocols in a general way.
@@ -238,7 +239,11 @@ public final class NIOSingleStepByteToMessageProcessor<Decoder: NIOSingleStepByt
}
@inlinable
func _decodeLoop(decodeMode: DecodeMode, seenEOF: Bool = false, _ messageReceiver: (Decoder.InboundOut) throws -> Void) throws {
func _decodeLoop(
decodeMode: DecodeMode,
seenEOF: Bool = false,
_ messageReceiver: (Decoder.InboundOut) throws -> Void
) throws {
// we want to call decodeLast once with an empty buffer if we have nothing
if decodeMode == .last && (self._buffer == nil || self._buffer!.readableBytes == 0) {
var emptyBuffer = self._buffer == nil ? ByteBuffer() : self._buffer!
+78 -67
View File
@@ -37,10 +37,10 @@ import struct WinSDK.sockaddr_un
import typealias WinSDK.u_short
fileprivate typealias in_addr = WinSDK.IN_ADDR
fileprivate typealias in6_addr = WinSDK.IN6_ADDR
fileprivate typealias in_port_t = WinSDK.u_short
fileprivate typealias sa_family_t = WinSDK.ADDRESS_FAMILY
private typealias in_addr = WinSDK.IN_ADDR
private typealias in6_addr = WinSDK.IN6_ADDR
private typealias in_port_t = WinSDK.u_short
private typealias sa_family_t = WinSDK.ADDRESS_FAMILY
#elseif canImport(Darwin)
import Darwin
#elseif os(Linux) || os(FreeBSD) || os(Android)
@@ -70,7 +70,7 @@ extension SocketAddressError {
/// Unable to parse a given IP ByteBuffer
public struct FailedToParseIPByteBuffer: Error, Hashable {
public var address: ByteBuffer
public init(address: ByteBuffer) {
self.address = address
}
@@ -85,10 +85,10 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
private let _storage: Box<(address: sockaddr_in, host: String)>
/// The libc socket address for an IPv4 address.
public var address: sockaddr_in { return _storage.value.address }
public var address: sockaddr_in { _storage.value.address }
/// The host this address is for, if known.
public var host: String { return _storage.value.host }
public var host: String { _storage.value.host }
fileprivate init(address: sockaddr_in, host: String) {
self._storage = Box((address: address, host: host))
@@ -100,10 +100,10 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
private let _storage: Box<(address: sockaddr_in6, host: String)>
/// The libc socket address for an IPv6 address.
public var address: sockaddr_in6 { return _storage.value.address }
public var address: sockaddr_in6 { _storage.value.address }
/// The host this address is for, if known.
public var host: String { return _storage.value.host }
public var host: String { _storage.value.host }
fileprivate init(address: sockaddr_in6, host: String) {
self._storage = Box((address: address, host: host))
@@ -115,7 +115,7 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
private let _storage: Box<sockaddr_un>
/// The libc socket address for a Unix Domain Socket.
public var address: sockaddr_un { return _storage.value }
public var address: sockaddr_un { _storage.value }
fileprivate init(address: sockaddr_un) {
self._storage = Box(address)
@@ -165,7 +165,7 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
@available(*, deprecated, renamed: "SocketAddress.protocol")
public var protocolFamily: Int32 {
return Int32(self.protocol.rawValue)
Int32(self.protocol.rawValue)
}
/// Returns the protocol family as defined in `man 2 socket` of this `SocketAddress`.
@@ -228,7 +228,7 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
}
}
}
/// Get the pathname of a UNIX domain socket as a string
public var pathname: String? {
switch self {
@@ -364,14 +364,14 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
addr.sin6_scope_id = 0
return .v6(.init(address: addr, host: ""))
} catch {
// If `inet_pton` fails as an IPv6 address (and has failed as an
// IPv4 address above), we will throw an error below.
// If `inet_pton` fails as an IPv6 address (and has failed as an
// IPv4 address above), we will throw an error below.
}
throw SocketAddressError.failedToParseIPString(ipAddress)
}
}
/// Create a new `SocketAddress` for an IP address in ByteBuffer form.
///
/// - parameters:
@@ -381,7 +381,7 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
/// - throws: may throw `SocketAddressError.failedToParseIPByteBuffer` if the IP address cannot be parsed.
public init(packedIPAddress: ByteBuffer, port: Int) throws {
let packed = packedIPAddress.readableBytesView
switch packedIPAddress.readableBytes {
case 4:
var ipv4Addr = sockaddr_in()
@@ -411,7 +411,7 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
internal init(ipv4MaskForPrefix prefix: Int) {
precondition((0...32).contains(prefix))
let packedAddress = (UInt32(0xFFFFFFFF) << (32 - prefix)).bigEndian
let packedAddress = (UInt32(0xFFFF_FFFF) << (32 - prefix)).bigEndian
var ipv4Addr = sockaddr_in()
ipv4Addr.sin_family = sa_family_t(AF_INET)
ipv4Addr.sin_port = 0
@@ -433,9 +433,9 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
// This defends against the possibility of a greater-than-/64 subnet, which would produce a negative shift
// operand which is absolutely not what we want.
let highShift = min(prefix, 64)
let packedAddressHigh = (UInt64(0xFFFFFFFFFFFFFFFF) << (64 - highShift)).bigEndian
let packedAddressHigh = (UInt64(0xFFFF_FFFF_FFFF_FFFF) << (64 - highShift)).bigEndian
let packedAddressLow = (UInt64(0xFFFFFFFFFFFFFFFF) << (128 - prefix)).bigEndian
let packedAddressLow = (UInt64(0xFFFF_FFFF_FFFF_FFFF) << (128 - prefix)).bigEndian
let packedAddress = (packedAddressHigh, packedAddressLow)
var ipv6Addr = sockaddr_in6()
@@ -455,9 +455,9 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
/// - returns: the `SocketAddress` for the host / port pair.
/// - throws: a `SocketAddressError.unknown` if we could not resolve the `host`, or `SocketAddressError.unsupported` if the address itself is not supported (yet).
public static func makeAddressResolvingHost(_ host: String, port: Int) throws -> SocketAddress {
#if os(Windows)
#if os(Windows)
return try host.withCString(encodedAs: UTF16.self) { wszHost in
return try String(port).withCString(encodedAs: UTF16.self) { wszPort in
try String(port).withCString(encodedAs: UTF16.self) { wszPort in
var pResult: UnsafeMutablePointer<ADDRINFOW>?
guard GetAddrInfoW(wszHost, wszPort, nil, &pResult) == 0 else {
@@ -482,10 +482,10 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
throw SocketAddressError.unsupported
}
}
#else
#else
var info: UnsafeMutablePointer<addrinfo>?
/* FIXME: this is blocking! */
// FIXME: this is blocking!
if getaddrinfo(host, String(port), nil, &info) != 0 {
throw SocketAddressError.unknown(host: host, port: port)
}
@@ -507,34 +507,36 @@ public enum SocketAddress: CustomStringConvertible, Sendable {
throw SocketAddressError.unsupported
}
} else {
/* this is odd, getaddrinfo returned NULL */
// this is odd, getaddrinfo returned NULL
throw SocketAddressError.unsupported
}
#endif
#endif
}
}
/// We define an extension on `SocketAddress` that gives it an elementwise equatable conformance, using
/// only the elements defined on the structure in their man pages (excluding lengths).
extension SocketAddress: Equatable {
public static func ==(lhs: SocketAddress, rhs: SocketAddress) -> Bool {
public static func == (lhs: SocketAddress, rhs: SocketAddress) -> Bool {
switch (lhs, rhs) {
case (.v4(let addr1), .v4(let addr2)):
#if os(Windows)
return addr1.address.sin_family == addr2.address.sin_family &&
addr1.address.sin_port == addr2.address.sin_port &&
addr1.address.sin_addr.S_un.S_addr == addr2.address.sin_addr.S_un.S_addr
#else
return addr1.address.sin_family == addr2.address.sin_family &&
addr1.address.sin_port == addr2.address.sin_port &&
addr1.address.sin_addr.s_addr == addr2.address.sin_addr.s_addr
#endif
#if os(Windows)
return addr1.address.sin_family == addr2.address.sin_family
&& addr1.address.sin_port == addr2.address.sin_port
&& addr1.address.sin_addr.S_un.S_addr == addr2.address.sin_addr.S_un.S_addr
#else
return addr1.address.sin_family == addr2.address.sin_family
&& addr1.address.sin_port == addr2.address.sin_port
&& addr1.address.sin_addr.s_addr == addr2.address.sin_addr.s_addr
#endif
case (.v6(let addr1), .v6(let addr2)):
guard addr1.address.sin6_family == addr2.address.sin6_family &&
addr1.address.sin6_port == addr2.address.sin6_port &&
addr1.address.sin6_flowinfo == addr2.address.sin6_flowinfo &&
addr1.address.sin6_scope_id == addr2.address.sin6_scope_id else {
return false
guard
addr1.address.sin6_family == addr2.address.sin6_family
&& addr1.address.sin6_port == addr2.address.sin6_port
&& addr1.address.sin6_flowinfo == addr2.address.sin6_flowinfo
&& addr1.address.sin6_scope_id == addr2.address.sin6_scope_id
else {
return false
}
var s6addr1 = addr1.address.sin6_addr
@@ -547,14 +549,13 @@ extension SocketAddress: Equatable {
let bufferSize = MemoryLayout.size(ofValue: addr1.address.sun_path)
// Swift implicitly binds the memory for homogeneous tuples to both the tuple type and the element type.
// This allows us to use assumingMemoryBound(to:) for managing the types. However, we add a static assertion here to validate
// that the element type _really is_ what we're assuming it to be.
assert(Swift.type(of: addr1.address.sun_path.0) == CChar.self)
assert(Swift.type(of: addr2.address.sun_path.0) == CChar.self)
return withUnsafePointer(to: addr1.address.sun_path) { sunpath1 in
return withUnsafePointer(to: addr2.address.sun_path) { sunpath2 in
withUnsafePointer(to: addr2.address.sun_path) { sunpath2 in
let typedSunpath1 = UnsafeRawPointer(sunpath1).assumingMemoryBound(to: CChar.self)
let typedSunpath2 = UnsafeRawPointer(sunpath2).assumingMemoryBound(to: CChar.self)
return strncmp(typedSunpath1, typedSunpath2, bufferSize) == 0
@@ -594,11 +595,11 @@ extension SocketAddress: Hashable {
hasher.combine(1)
hasher.combine(v4Addr.address.sin_family)
hasher.combine(v4Addr.address.sin_port)
#if os(Windows)
#if os(Windows)
hasher.combine(v4Addr.address.sin_addr.S_un.S_addr)
#else
#else
hasher.combine(v4Addr.address.sin_addr.s_addr)
#endif
#endif
case .v6(let v6Addr):
hasher.combine(2)
hasher.combine(v6Addr.address.sin6_family)
@@ -612,7 +613,6 @@ extension SocketAddress: Hashable {
}
}
extension SocketAddress {
/// Whether this `SocketAddress` corresponds to a multicast address.
public var isMulticast: Bool {
@@ -624,15 +624,15 @@ extension SocketAddress {
// For IPv4 a multicast address is in the range 224.0.0.0/4.
// The easy way to check if this is the case is to just mask off
// the address.
#if os(Windows)
#if os(Windows)
let v4WireAddress = v4Addr.address.sin_addr.S_un.S_addr
let mask = UInt32(0xF000_0000).bigEndian
let subnet = UInt32(0xE000_0000).bigEndian
#else
#else
let v4WireAddress = v4Addr.address.sin_addr.s_addr
let mask = in_addr_t(0xF000_0000 as UInt32).bigEndian
let subnet = in_addr_t(0xE000_0000 as UInt32).bigEndian
#endif
#endif
return v4WireAddress & mask == subnet
case .v6(let v6Addr):
// For IPv6 a multicast address is in the range ff00::/8.
@@ -649,13 +649,22 @@ protocol SockAddrProtocol {
}
/// Returns a description for the given address.
internal func descriptionForAddress(family: NIOBSDSocket.AddressFamily, bytes: UnsafeRawPointer, length byteCount: Int) throws -> String {
internal func descriptionForAddress(
family: NIOBSDSocket.AddressFamily,
bytes: UnsafeRawPointer,
length byteCount: Int
) throws -> String {
var addressBytes: [Int8] = Array(repeating: 0, count: byteCount)
return try addressBytes.withUnsafeMutableBufferPointer { (addressBytesPtr: inout UnsafeMutableBufferPointer<Int8>) -> String in
try NIOBSDSocket.inet_ntop(addressFamily: family, addressBytes: bytes,
addressDescription: addressBytesPtr.baseAddress!,
addressDescriptionLength: socklen_t(byteCount))
return addressBytesPtr.baseAddress!.withMemoryRebound(to: UInt8.self, capacity: byteCount) { addressBytesPtr -> String in
return try addressBytes.withUnsafeMutableBufferPointer {
(addressBytesPtr: inout UnsafeMutableBufferPointer<Int8>) -> String in
try NIOBSDSocket.inet_ntop(
addressFamily: family,
addressBytes: bytes,
addressDescription: addressBytesPtr.baseAddress!,
addressDescriptionLength: socklen_t(byteCount)
)
return addressBytesPtr.baseAddress!.withMemoryRebound(to: UInt8.self, capacity: byteCount) {
addressBytesPtr -> String in
String(cString: addressBytesPtr)
}
}
@@ -663,14 +672,14 @@ internal func descriptionForAddress(family: NIOBSDSocket.AddressFamily, bytes: U
extension sockaddr_in: SockAddrProtocol {
func withSockAddr<R>(_ body: (UnsafePointer<sockaddr>, Int) throws -> R) rethrows -> R {
return try withUnsafeBytes(of: self) { p in
try withUnsafeBytes(of: self) { p in
try body(p.baseAddress!.assumingMemoryBound(to: sockaddr.self), p.count)
}
}
/// Returns a description of the `sockaddr_in`.
func addressDescription() -> String {
return withUnsafePointer(to: self.sin_addr) { addrPtr in
withUnsafePointer(to: self.sin_addr) { addrPtr in
// this uses inet_ntop which is documented to only fail if family is not AF_INET or AF_INET6 (or ENOSPC)
try! descriptionForAddress(family: .inet, bytes: addrPtr, length: Int(INET_ADDRSTRLEN))
}
@@ -679,14 +688,14 @@ extension sockaddr_in: SockAddrProtocol {
extension sockaddr_in6: SockAddrProtocol {
func withSockAddr<R>(_ body: (UnsafePointer<sockaddr>, Int) throws -> R) rethrows -> R {
return try withUnsafeBytes(of: self) { p in
try withUnsafeBytes(of: self) { p in
try body(p.baseAddress!.assumingMemoryBound(to: sockaddr.self), p.count)
}
}
/// Returns a description of the `sockaddr_in6`.
func addressDescription() -> String {
return withUnsafePointer(to: self.sin6_addr) { addrPtr in
withUnsafePointer(to: self.sin6_addr) { addrPtr in
// this uses inet_ntop which is documented to only fail if family is not AF_INET or AF_INET6 (or ENOSPC)
try! descriptionForAddress(family: .inet6, bytes: addrPtr, length: Int(INET6_ADDRSTRLEN))
}
@@ -695,7 +704,7 @@ extension sockaddr_in6: SockAddrProtocol {
extension sockaddr_un: SockAddrProtocol {
func withSockAddr<R>(_ body: (UnsafePointer<sockaddr>, Int) throws -> R) rethrows -> R {
return try withUnsafeBytes(of: self) { p in
try withUnsafeBytes(of: self) { p in
try body(p.baseAddress!.assumingMemoryBound(to: sockaddr.self), p.count)
}
}
@@ -703,7 +712,7 @@ extension sockaddr_un: SockAddrProtocol {
extension sockaddr_storage: SockAddrProtocol {
func withSockAddr<R>(_ body: (UnsafePointer<sockaddr>, Int) throws -> R) rethrows -> R {
return try withUnsafeBytes(of: self) { p in
try withUnsafeBytes(of: self) { p in
try body(p.baseAddress!.assumingMemoryBound(to: sockaddr.self), p.count)
}
}
@@ -714,21 +723,23 @@ extension sockaddr_storage: SockAddrProtocol {
// the compiler falls over when we try to access them from test code. As these functions
// exist purely to make the behaviours accessible from test code, we name them truly awfully.
func __testOnly_addressDescription(_ addr: sockaddr_in) -> String {
return addr.addressDescription()
addr.addressDescription()
}
func __testOnly_addressDescription(_ addr: sockaddr_in6) -> String {
return addr.addressDescription()
addr.addressDescription()
}
func __testOnly_withSockAddr<ReturnType>(
_ addr: sockaddr_in, _ body: (UnsafePointer<sockaddr>, Int) throws -> ReturnType
_ addr: sockaddr_in,
_ body: (UnsafePointer<sockaddr>, Int) throws -> ReturnType
) rethrows -> ReturnType {
return try addr.withSockAddr(body)
try addr.withSockAddr(body)
}
func __testOnly_withSockAddr<ReturnType>(
_ addr: sockaddr_in6, _ body: (UnsafePointer<sockaddr>, Int) throws -> ReturnType
_ addr: sockaddr_in6,
_ body: (UnsafePointer<sockaddr>, Int) throws -> ReturnType
) rethrows -> ReturnType {
return try addr.withSockAddr(body)
try addr.withSockAddr(body)
}

Some files were not shown because too many files have changed in this diff Show More