Commit Graph
321 Commits
Author SHA1 Message Date
Si BeaumontandAgam Dua b0e024792a Add opt-in API for channels to expose their underlying transport (#3509)
## Motivation

NIO channels abstract over an underlying transport mechanisms (sockets,
pipes, etc.), which users typically need not interact with. However,
there are scenarios where users need direct access to the underlying
transport for low-level operations that work outside NIOs abstraction.
One example is performing out out-of-band operations on the underlying
file descriptor for a socket-based channel.

This PR adds a structured way to access the underlying transport of a
channel, for channels that choose to implement it.

## Modifications

- Add a new `public protocol
NIOTransportAccessibleChannelCore<Transport>` which provides a scoped
`withUnsafeTransport(_:)`, used for channel implementations to opt-in.
- Add conformance to
`NIOTransportAccessibleChannel<NIOBSDSocket.Handle>` for
`BaseSocketChannel`, to make this API available for all socket-based
channels, including channels returned from the socket-based bootstrap
public APIs.
- Add public API
`ChannelPipeline.SynchronousOperations.withUnsafeTransportIfAvailable(_:)`

Note that not all channels need to or should their transport, which is
why this was added as an additional protocol that refines `ChannelCore`,
vs. extending `Channel` or `ChannelCore` with a default implementation.

The protocol uses a primary associated type allowing channels to provide
typed access to the transport. E.g. this could be used in NIO Transport
Services to expose the underlying `NWConnection`, if desired.

The method itself is spelled with "unsafe", uses scoped access, and has
clear documentation that users must not violated any of NIOs assumptions
about the state of the underlying transport. It's very much not intended
for every day use. It being on `ChannelCore` should defer users of the
low-level API, since `Channel._channelCore` is marked as for NIO
internal use, and the public `withUnsafeTransportIfAvailable(_:)` will
take care of the runtime checks for channels that have opted into this
API.

## Result

- New opt-in API for channel implementations to expose their underlying
transport
- All socket-based channels from NIOPosix now expose the underlying
socket file descriptor
- New API
`ChannelPipeline.SynchronousOperations.withUnsafeTransportIfAvailable(_:)`
for users

---------

Co-authored-by: Agam Dua <agam_dua@apple.com>
2026-02-17 16:12:58 +00:00
Fabian Fett 6a6f7d7c33 Centralize UnsafeTransfer in NIOCore (#3492)
We have a number of copies of `UnsafeTransfer` and two copies of
`UnsafeMutableTransferBox` in our code base. Before introducing more of
those, lets centralize to just one using a `package` access modifier.
2026-02-03 10:27:30 +00:00
Karan Lokchandani 4a9a971110 docs: String(buffer:) needs to mention that it will always succeed (#3476)
### Motivation:
The documentation for String(buffer:) initializer does not clearly
indicate
that this operation will always succeed, which may leave developers
uncertain
about error handling requirements.
fixes: https://github.com/apple/swift-nio/issues/3449

### Modifications:
Updated the documentation for String(buffer:) to explicitly mention that
the initialization will always succeed.

### Result:
Developers will have clearer understanding that String(buffer:) is a
safe
operation that does not require error handling.

Signed-off-by: Karan <karanlokchandani@protonmail.com>
2026-01-08 15:58:15 +00:00
e3d5c560e0 Fix coreCount on Linux when using cgroup v2 with CFS throttling disabled (#3462)
Fix coreCount on Linux when using cgroup v2 with CFS throttling disabled

### Motivation:

When using `swift-nio` on Linux with cgroup v2 enabled, but with CFS
throttling disabled, it falls back to attempting to read the cpuset file
at the cgroup v1 path. This does not exist, which in turns falls back to
returning `_SC_NPROCESSORS_ONLN`, which will return the total number of
cores available (ignoring cgroup assignments).

This has unexpected effects, including the default behaviour of starting
the `MultiThreadedEventLoopGroup.singleton` with significantly more
event loops than cores available to the workload.

### Modifications:

- Adds `SystemCalls.statfs`, and associated constants, to determine the
cgroup version.
- Adds `Linux.cgroupVersion()` API to expose cgroup version.
- Adds `Linux.cgroupV2MountPoint` variable to determine the cgroup v2
mount point.
- Adds `Linux.cpuSetPathV1` & `Linux.cpuSetPathV2` (and
`Linux.cpuSetPath` convenience) variables to determine the correct cpu
set path.
- Alters `System.coreCount` to use the appropriate logic from above to
ensure that `cpuset.cpus` is parsed from the correct location.

### Result:

`Linux.coreCount` should correctly parse and return the core count on
Linux cgroup v2 enabled systems (when CFS throttling is disabled), while
maintaining correctness for other configurations.

---------

Co-authored-by: Johannes Weiss <johannesweiss@apple.com>
Co-authored-by: Cory Benfield <lukasa@apple.com>
2026-01-05 14:26:21 +00:00
aryan-25 a1605a3303 Use explicit class name in all Self.[un]wrap{In}{Out}bound{In}{Out} calls (#3463)
### Motivation:

Swift does not currently generic specialize static methods on final
classes that have no parent classes when the method is implemented in a
protocol. This means that calling such methods through `Self` will not
involve a generic specialization, whereas using the explicit type name
will.

This pattern manifests in the `[un]wrap{In}{Out}bound{In}{Out}` static
methods defined in the
[`ChannelInboundHandler`](https://github.com/apple/swift-nio/blob/27146d484478b1bb0f150e848758f3a34ed9cbd0/Sources/NIOCore/TypeAssistedChannelHandler.swift#L60)
and
[`ChannelOutboundHandler`](https://github.com/apple/swift-nio/blob/27146d484478b1bb0f150e848758f3a34ed9cbd0/Sources/NIOCore/TypeAssistedChannelHandler.swift#L95)
protocols and their use from all channel handler classes. As such, we
should replace the `Self` part in all
`Self.[un]wrap{In}{Out}bound{In}{Out}` calls with the explicit class
name.

### Modifications:

Replaced all `Self.[un]wrap{In}{Out}bound{In}{Out}` calls to use the
explicit class name.

### Result:

Eliminates unnecessary overhead.
2025-12-15 17:36:11 +00:00
Adam Fowler 888f4affd6 Add ByteBuffer.readableBytesUInt8Span (#3458)
Add  ByteBuffer.readableBytesUInt8Span

### Motivation:

Provide access to readableBytes as a Span<UInt8>

### Modifications:

Added computed property `ByteBuffer.readableBytesUInt8Span`. I also
attempted to add `ByteBuffer.mutableReadableBytesUInt8Span` but due to
an apparently faulty exclusivity issue I couldn't get this to work. See
https://github.com/swiftlang/swift/issues/81218.

### Result:

You can access the readable bytes of a ByteBuffer as a Span<UInt8>
2025-12-05 15:32:17 +00:00
Rafael Cepeda b60d141920 Document when channel.remoteAddress field can be nil (#3456)
Added extra documentation to `channel.remoteAddress` field to capture a
scenario where this field might be `nil`

### Motivation:

It is somewhat common for users to have code like
`channel.remoteAddress!` in their implementation, as it is a reasonable
assumption to think a socket connection will have an associated remote
address. However, in at least one known situation this might not be the
case. When that happens, user's code might crash due to the force unwrap
of the optional field.

### Modifications:

Introduced more documentation to make it clear that users should be
prepared to handle the `nil` scenario.

### Result:

Less frequent mishandling of `channel.remoteAddress`.
2025-12-01 11:09:56 +00:00
3405691582andRick Newton-Rogers 2bc71a6aff Partial OpenBSD support. (#3394)
### Motivation:

Additional partial platform support.

### Modifications: 

* Create a new CNIOBSD module for OpenBSD, for general cleanliness, and
make use of it throughout. Some of the changes are borrowed directly
from CNIOLinux; some may technically be unnecessary; I am erring
somewhat on expediency to functionality.

* Since `malloc_size` is unavailable on OpenBSD, and some of the helpers
make use of ManagedBufferPointer which makes use of it, mark some of
this as unavailable as well.

* Usual pthread optional typing changes, since pthread types are
pointers on this platform.

* Add conditionals to exclude other functionality not available here,
like IP_RECVPKTINFO or IP_PKTINFO.

* d_ino is a backwards-compatibility macro valued token for dirent, so
instead, just expand with a conditional.

* Use kqueue on OpenBSD. This necessitates adding some conditionals for
type and feature compatibility.

* The vsock API is unavailable on OpenBSD.

### Result:

Tested the NIOTCPEchoClient and NIOTCPEchoServer appears to work and
that swift-nio-ssh (hopefully wlog) builds with a local repository with
these changes.

Because NIOFS/_NIOFileSystem depend on some non-portable components,
such as extended attributes, sendfile, non-portable linkat flags, and
renameat2, this is only just partial OpenBSD support, which means that
`swift build` on the full swift-nio project won't build cleanly, but at
least the portable parts can be used to build servers and clients. This
commit will mark the linked bug as fixed; I will open a new bug for file
system support.

Fixes #3383.

---------

Co-authored-by: Rick Newton-Rogers <rnro@apple.com>
2025-11-26 09:07:02 +00:00
George Barnett cda536de37 Dont hold lock over continuation in NIOThrowingAsyncSequenceProducer (#3454)
Motivation:

The various 'withMumbleContinuation' APIs are supposed to be invoked
synchronously with the caller. This assumption allows a lock to be
acquired before the call and released from the body of the
'withMumbleContinuation' after e.g. storing the continuation. However
this isn't the case and the job may be re-enqueued on the executor
meaning that this is pattern is vulnerable to deadlocks.

Modifications:

- Drop and reacquire the lock in the NIOThrowingAsyncSequenceProducer.
- Merge 'next()' and 'next(for:)' methods in the state machine into a
single func; this reduces the amount of duplicated logic across the two
functions.

Result:

Lower chance of deadlock
2025-11-25 09:39:54 +00:00
George Barnett d2feeaa363 Handle cancellation between dropping and reaquiring lock (#3453)
Motivation:

This is a follow up to 5bf841dd to handle the yield task being cancelled
between dropping the lock and re-acquiring it a moment later in the
'withContinuation' block.

Modifications:

- Add an extra cancellation check when yielding with a continuation.

Result:

Fewer issues
2025-11-25 09:16:35 +00:00
George Barnett 5bf841dde5 Drop and reacquire lock over continuation call (#3452)
Motivation:

The various 'withMumbleContinuation' APIs are supposed to be invoked
synchronously with the caller. This assumption allows a lock to be
acquired before the call and released from the body of the
'withMumbleContinuation' after e.g. storing the continuation. However
this isn't the case and the job may be re-enqueued on the executor
meaning that this is pattern is vulnerable to deadlocks.

Modifications:

- Drop and reacquire the lock in the NIOAsyncWriter

Result:

Lower chance of deadlock
2025-11-24 11:13:50 +00:00
Max Desiatov 6e02c7a246 Make ByteBuffer.writeBytes(_: RawSpan) broadly available (#3447)
`RawSpan` can be back-deployed, so availability can become consistent
with similar methods like this one
https://github.com/apple/swift-nio/blob/56724a2b6d8e2aed1b2c5f23865b9ea5c43f9977/Sources/NIOCore/ByteBuffer-aux.swift#L1020C3-L1024C38
2025-11-17 09:22:35 +00:00
Fabian Fett 45b463c5eb Quality of Life: Add NIOLoopBoundBox.withValue (#3385)
When having a state machine inside the `NIOLoopBoundBox` we currently
check the EL when reading and writing. This is unnecessary. Because of
this, this PR introduces a new `withValue` method, that allows users to read and
write the value inside the NIOLoopBoundBox while only paying the cost
for the EL check once.
2025-11-10 10:08:50 -05:00
Cory Benfield 5741df9cc4 Enable per-message GRO on Linux (#3439)
Motivation:

NIO has existing GRO support. This GRO support is applied at Channel
scope, which makes it somewhat less than ideal, as it forces the
datagram sizes to be accessed using socket options. In real applications
this is less desirable than being able to do this on a per-superbuffer
context.

Linux supports this already by using recvmsg/recvmmsg control data. We
just need to wire this up in NIO. We can re-use the existing metadata
fields on AddressedEnvelope.

Modifications:

- Add a new ChannelOption to extra metadata
- Reject setting this option on non-Linux devices.
- On Linux, use this to load the control data.
- Added new tests that validate the behaviour is correct.

Result:

Enable per-message GRO.
2025-11-07 13:24:30 -05:00
Cory Benfield a7da98c3ac Enable per-message GSO on Linux (#3436)
Motivation:

NIO has existing GSO support. This GSO support is applied at Channel
scope, which makes it somewhat less than ideal, as it forces the
datagram sizes to be known statically ahead of time. In real
applications this is less common than being able to do this on a
per-superbuffer
context.

Linux supports this already by using sendmsg/sendmmsg control data. We
just need to wire this up in NIO.

An extension to this is that we can also do per-message GRO in Linux.
I'll tackle this in a later patch to keep the diffs small.

Modifications:

- Adding a new field on AddressedEnvelope Metadata.
- Reject setting this field on non-Linux devices.
- On Linux, use this to set the control data.
- Added new tests that validate the behaviour is correct.

Result:

Enable per-message GSO.
2025-11-07 08:34:33 +00:00
Cory Benfield 88dc99031f Add some spans to ByteBuffer (#3371)
Motivation:

Users would like to be able to access the underlying memory of a
ByteBuffer, as evidenced by the plethora of `withUnsafe*` methods that
ByteBuffer has. As Swift 6.2 has introduced some initial APIs for safe
memory access to underlying storage, we should offer similar APIs on
ByteBuffer to enable users to get safer access to that storage.

For now, the obvious APIs to be able to supplement are:

- withUnsafeReadableBytes
- withUnsafeMutableReadableBytes
- writeWithUnsafeMutableWritableBytes

We can also offer some new APIs to allow initializing a buffer directly
from an OutputSpan.

Note that we can only do this because the Language Steering Group has
pinky promised that they will not break the "Lifetimes" experimental
feature: see

https://forums.swift.org/t/experimental-support-for-lifetime-dependencies-in-swift-6-2-and-beyond/78638
for more details. We are taking them at their word, and so we are
enabling that feature.

Modifications:

Many new methods and tests.

Result:

Safer access.
2025-11-06 11:54:06 -05:00
Cory Benfield fd7c6af4f0 Replace rethrows with typed throws in ByteBuffer (#3372)
Motivation:

Users who want to use typed throws would benefit from us propagating the
thrown error type through our APIs. Most of our surface doesn't allow
for that because it relies on standard library APIs that haven't been
updated, but we can do it for ByteBuffer which is entirely ours.

Modifications:

- Adopt typed rethrows in ByteBuffer

Result:

Users have an easier time working with ByteBuffer
2025-11-05 16:14:30 -05:00
scottmarchant e304a1a363 chore: For WASI builds only, use fatalError in all .wait() calls. Recommend using .get() instead. (#3421)
Use fatalError in all .wait() calls for WASI builds only, and point
developers towards .get() instead.

### Motivation:

While working to adopt NIO in some wasm code, I've commonly ran into
issues any time code calls `.wait()` during wasm runtime. Typically the
executable either traps or crashes any time `.wait()` is called with an
ambiguous error: `Uncaught (in promise) RuntimeError: Atomics.wait
cannot be called in this context`. The error occurs because it is
forbidden to block the main thread for a wasm executable, and the
current implementation of `.wait()` blocks the calling thread.

The fix is straight forward, all calls to `.wait()` need refactor to
`.get()`, which sometimes involves some Swift Concurrency adoption (eg.
`async`) in the process. That change avoids blocking the main thread.

### Modifications:

Added `fatalError` with a descriptive error message to help developers
identify the issue easier.

### Result:

For WASI builds only, changes the trap error message `Uncaught (in
promise) RuntimeError: Atomics.wait cannot be called in this context`
into the following error message instead:

```
NIO's wait() function should not be called on WASI platforms. It will freeze or crash. Use get() instead.
```

### Alternatives considered

- We could instead conditionalize `.wait()` completely out of nio for
WASI builds, to turn runtime errors into compiler errors. That makes
detection of this issue easier, but forces a refactor and breaking
change, and somewhat precludes the possibility that WASI might support
this down the road with a future change.
- We could add a deprecation for WASI only. But long term WASI may be
able to support this blocking call, so deprecation and removal is
communicating the wrong message if the future ends up being reality.

### Context

This PR is [part of a larger effort by
PassiveLogic](https://github.com/PassiveLogic/swift-web-examples/issues/1)
to move Swift for WebAssembly support forward in a large number of
dependencies.
2025-11-03 12:50:23 -05:00
Mahdi Bahrami 0469372396 Implement AsyncSequence/splitLines() (#3411)
~~Implement `AsyncSequence/split()` functions similar to
`String/split()` functions in std-lib.~~
Implement `AsyncSequence/splitLines()` functions similar to
`String/split(whereSeparator: \.isNewline)` in std-lib.

### Motivation:

~~Provide an easy way for users to split the data incoming from an async
sequence, using their preferred separator.~~
Provide an easy way for users to split the data incoming from an async
sequence, on new lines.

### Modifications:

Add `internal SplitMessageDecoder: NIOSingleStepByteToMessageDecoder`.
Add `public NIOSplitLinesMessageDecoder:
NIOSingleStepByteToMessageDecoder`.
Add `public
AsyncSequence/splitLines(omittingEmptySubsequences:maximumBufferSize) ->
AsyncSeq<ByteBuffer>`.
Add `public
AsyncSequence/splitUTF8Lines(omittingEmptySubsequences:maximumBufferSize)
-> AsyncSeq<String>`.

### Result:

Users can easily split the data.
2025-10-21 16:13:43 +01:00
Mahdi Bahrami f2ad915d57 [perf] Manually implement lastIndex(where:) in ByteBufferView (#3413)
### Motivation:

`ByteBuffer.lastIndex(where:)` is of suboptimal performance.
The default Collection implementations don't go through any "magic
underscored" functions like `_customIndexOfEquatableElement`.

### Modifications:

Manually implement `lastIndex(where:)`.

### Result:

Basically free performance boost. 2x+ boost even for not big buffers of
a few hundred bytes.

This function is currently used in
`ByteBufferView.trim(limitingElements:)`.

I have no immediate use case for this function, but it's still an issue
worth addressing.
2025-10-21 14:02:55 +01:00
Mahdi Bahrami 767ea9ee09 [perf] Manually implement firstIndex(where:) in ByteBufferView (#3412)
### Motivation:

`ByteBuffer.firsIndex` is of suboptimal performance.
The default Collection implementations don't go through any "magic
underscored" functions like `_customIndexOfEquatableElement`.

### Modifications:

Manually implement `firstIndex(where:)`.

### Result:

Basically free performance boost. 2x+ boost even for not big buffers of
a few hundred bytes.

There are some usage of this function in `BufferedReader`. Those will
become much faster.
Also this function is used in `ByteBufferView.trim(limitingElements:)`.

Also makes #3411 stuff faster. See:
https://github.com/apple/swift-nio/pull/3411#discussion_r2436260691
2025-10-17 07:15:44 +00:00
Mahdi Bahrami 86c5ead5dd Introduce NIODecodedAsyncSequence for easy decoding of async sequences (#3407)
Previous PR: #3405 

Add an API on top of `AsyncSequence<ByteBuffer>` which can dynamically
decode values.
~~Add an API on top of the new `AsyncSequence<ByteBuffer>` APIs which
splits the file based on its content.~~

### Motivation:

Provides a nice API to decode files, instead of users having to go
though manually handling `BufferedReader.read(while:)`.
I struggled with this, as documented in
https://swift-open-source.slack.com/archives/C9MMT6VGB/p1760115481607159

### Modifications:

Add `NIODecodedAsyncSequence` + functions on `AsyncSequence<ByteBuffer>`
to create such a sequence.
~~Add `NIOSplitMessageDecoder` + stdlib-like functions on
`AsyncSequence<ByteBuffer>` to create such a sequence.~~

### Result:

Users can decode an async sequence of `ByteBuffer`s easier.
~~Users can easily split files based on their content.~~

### Checklist

See this comment for a checklist of the remaining things to do:
https://github.com/apple/swift-nio/pull/3407#issuecomment-3403382404
2025-10-16 09:49:55 +00:00
Fabian FettandCory Benfield a3ed8e10ab Drop Swift 5.10 (#3393)
This PR drops Swift 5.10 and enables Swift 6 language mode.

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
2025-10-06 10:58:33 +01:00
Mahdi BahramiandCory Benfield 2e22c89844 Add InlineArray helpers to ByteBuffer (#3252)
### Motivation:

Useful for parsing packets, for example `ipv4: InlineArray<4, UInt8>`
and `ipv6: InlineArray<16, UInt8>`.

### Modifications:

For now I've only added a `readInlineArray` function. I know some other
functions are missing, such as `writeInlineArray`.
I wanted to first open up a discussion and see if these changes are
acceptable. I can add those functions too if required, in this PR or
other PRs.

### Result:

Users can read `ByteBuffer` into stack-allocated memory, which can be
more performant than the other alternatives like `Array`, or more
convenient than reading as a tuple like `(UInt8, UInt8, UInt8, UInt8)`.

### Caveats:

Swift 6.2 is required so I've used `#if compiler(>=6.2)`.
Furthermore, `InlineArray` is marked as available on `macOS(9999)` since
the Swift team have yet to update that mark, although `InlineArray` is
planned for Swift 6.2 per the
[proposal](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0453-vector.md).

Edit: to be clear things work fine on Linux and that's where I've been
using this same `readInlineArray` function that I've proposed.

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
2025-09-24 09:18:00 +00:00
Cory Benfield f2ebedb36a The formatter changed its mind (#3379) 2025-09-23 14:58:24 +01:00
Fabian Fett 5679824930 [Windows] Ensure WSAStartup is correctly called. (#3366)
### Motivation

- `WSAStartup` isn't called

### Changes

- Change stuff that I have very little idea about until it works

### Result

WSAStartup is now emitted at the correct location for the linker to be
picked up.
2025-09-03 16:16:21 +00:00
Fabian Fett 456921a854 [Windows] Fix getenv warnings in NIOPosix and NIOEmbedded (#3351)
Less yellow code.
2025-08-19 12:48:46 +00:00
Fabian Fett 93102a85ee [Windows] Fix deprecation warnings in NIOCore (#3345)
- `getenv` and `strerror` are deprecated in Windows land
- replace with undeprecated alternatives
- result: less yellow in the build log
2025-08-14 14:04:40 +01:00
Rafael Cepeda 02be63c7f4 Fixes all warnings when -require-explicit-sendable flag is enabled (#3320)
Fixes all warnings when `-require-explicit-sendable` flag is enabled and
enables the flag on macOS CI.

### Motivation:

We want to ensure our public API is either explicitly marked as
`Sendable` or not.

### Modifications:

Marked appropriate public types as `Sendable`, or explicitly defined
their conformance to the `Sendable` protocol as unavailable.

### Result:

We can now enable `-require-explicit-sendable` compiler flag in our
codebase.
2025-07-30 11:50:28 +01:00
George BarnettandCory Benfield 664032bdd6 Wrap closures stored in the CallbackList (#3303)
Motivation:

The compiler is better at optimising closures wrapped in nominal types
than raw closures when used as generic parameters. CallbackList is used
a lot and stores an optional closure as well as on optional array of
closures. Wrapping these internally should save some allocations.

Modifications:

- Wrap the element stored in the `CallbackList`.

Result:

Fewer allocs

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
2025-07-14 16:48:26 +00:00
Johannes Weiss 0b65385fad improve inEventLoop checks (#3302)
### Motivation:

`inEventLoop` is very much in the performance path of SwiftNIO,
especially these days with Concurrency, `NIOLoopBound` and friends.
Previously, we relied on `pthread_equal(pthread_self(), myPthread)`,
however, this could cause a number of issues.

1. Holding onto a `pthread_t` after `.join` is actually illegal (fixed
in #3297)
2. Potential ABA issues when `pthread_t` pointer are re-used for new
pthreads
3. Fix would require a lock around `myPthread` which makes things (2x
slower, even without contention)

### Modifications:

- New type `SelectableEventLoopUniqueID` which can be packed into a
`UInt`
- Attach them into a C thread local

### Result:

- Even faster than the old, incorrect version
- old: `measuring: el_in_eventloop_100M: 0.257395375, 0.241049208,
0.243188792, 0.259125916, 0.24843225, 0.229690125, 0.244281541,
0.225078834, 0.236395, 0.233305167`
- new: `measuring: el_in_eventloop_100M: 0.175561125, 0.187225625,
0.199269375, 0.19740975, 0.1922695, 0.179850958, 0.177612458,
0.17665125, 0.17897475, 0.18038775`
- More correct
- Groundwork to make #3297 not make things slower
2025-07-14 17:15:10 +01:00
scottmarchant 15dfe081a1 fix: Fix compiler error found on latest main that breaks wasip1 (wasm) compilation (#3271)
This is a quick simple fix for compiling NIOCore to wasm using the
command `swift build --swift-sdk wasm32-unknown-wasip1-threads --target
NIOCore`.

This fixes all errors for `wasip1`, however there are other errors
remaining in `main` when compiling for `wasi` using the command `swift
build --swift-sdk wasm32-unknown-wasi --target NIOCore`. Those issues
are out of scope for this PR.

### Motivation:

I am working to enable wasm compilation for a wide range of repositories
which depend on NIOCore. See
[here](https://github.com/PassiveLogic/swift-web-examples/issues/1) for
a sneak peak. This change is required to enable compiling several
respositories.

### Modifications:

`.multicastNotSupported` is elided for `os(WASI)` builds in
Channel.swift, however some new code referenced that case without proper
`WASI` guards.

This modification simply adds the appropriate elision guard to fix
wasip1 builds for NIOCore.

### Result:

After making this change, `swift build --swift-sdk
wasm32-unknown-wasip1-threads --target NIOCore` builds again (assuming
you have the appropriate wasm sdk installed).
2025-06-24 09:52:12 +00:00
Paul ToffoloniandFabian Fett 8d2347a56b Add scheduleCallback APIs to NIOIsolatedEventLoop (#3263)
Fixes #3262 by adding the missing APIs.

### Motivation:

As explained by the issue linked above, having a
non-`Sendable`-requiring variant of the new `scheduleCallback` APIs on
`NIOIsolatedEventLoop` can be useful since we're not always dealing with
`Sendable` types.

### Modifications:

This adds the required `scheduleCallback` APIs to `NIOIsolatedEventLoop`
by wrapping the non-`Sendable` `NIOScheduleCallbackHandler` in a
`NIOLoopBound`-based handler.
### Result:

The two `scheduleCallback`s can be used on `NIOIsolatedEventLoop` too.

---------

Co-authored-by: Fabian Fett <fabianfett@apple.com>
2025-06-18 14:54:33 +01:00
Orhan Yigit Yazicilar cddbde511a Adding RawSpan support to writeBytes in ByteBuffer (#3269)
Motivation:

With the new Swift version (6.2) we get access to spans for safely
interacting with the contiguous memory owned by other types. Allow users
write bytes to the ByteBuffer with RawSpans.

Modifications:

* ByteBuffer-core: Overload the setBytes, _setBytes, and
_setBytesAssumingUniqueBufferAccess to use RawSpan instead of
UnsafeRawBufferPointer
* ByteBuffer-aux: Overload the writeBytes to use RawSpan instead of
UnsafeRawBufferPointer

Result:

Users can now write the contiguous memory of other types into ByteBuffer
using the new RawSpan overloads, removing the need for unsafe pointer
handling.
2025-06-16 17:11:03 +00:00
Cory Benfield c9e2ac115f Adjust for SendableMetatype (#3266)
Motivation

With the introduction of isolated conformances, it has become necessary
to start managing the use of metatypes for some of our protocols. In
general, we don't want to force the relevant protocols to only be
conformed in non-isolated forms. Instead, we just want to make the
specific APIs non-usable.

Modifications

- Add shims for SendableMetatype that only use it when it is available.
- Require SendableMetatype where needed, gated by @preconcurrency.

Result

We continue to be safe.
2025-06-13 09:12:25 +01:00
Roman A f3645a02b7 a couple grammar fixes (#3259) 2025-05-30 10:34:44 +00:00
Fabian FettandGeorge Barnett fec9719099 NIOThrowingAsyncSequenceProducer make more funcs @inlinable (#3243)
When working on performance in PostgresNIO I noticed a few
`_swift_getGenericMetadata`s. We don't like those. I could trace them
down to `NIOThrowingAsyncSequenceProducer`. All methods on this object
are generic, since the object itself is generic.

Co-authored-by: George Barnett <gbarnett@apple.com>
2025-05-23 13:43:07 +00:00
Rick Newton-Rogers 14dcafc6ec Update Array+FileSystem.swift to add visionOS (#3220)
Fix visionOS builds and tests

### Motivation:

visionOS builds and tests were failing because of missing cases in
availability guards.

### Modifications:

Spell guards in terms of Darwin where appropriate, add visionOS

### Result:

Example run of this working in CI
https://github.com/apple/swift-nio/actions/runs/14876166161/job/41773757638?pr=3220
2025-05-07 13:22:23 +00:00
Rafael CepedaandGeorge Barnett afa7d4f57d Moving PooledRecvBufferAllocator from NIOPosix to NIOCore (#3110)
Moving `PooledRecvBufferAllocator` from NIOPosix to NIOCore, making it
part of its public interface.

### Motivation:

We want to introduce the capability of reusing receiving buffers from a
pool into swift-nio-transport-services project. To prevent duplicating
this functionality there, this change is making the existing
functionality from NIO part of its public API.

### Modifications:

Moved the type `PooledRecvBufferAllocator` from NIOPosix module to
NIOCore and turned it into a public type.

### Result:

`PooledRecvBufferAllocator` is part of NIOCore public API.

---------

Co-authored-by: George Barnett <gbarnett@apple.com>
2025-05-07 12:50:15 +00:00
Axel AnderssonandGeorge Barnett 960dcfb29b Make ChannelError and NIOConnectionError conform to CustomStringConvertible (#3230)
### Motivation:

`ChannelError` and `NIOConnectionError` should conform
`CustomStringConvertible` so that these errors can be easily logged.

As discussed in https://github.com/apple/swift-nio/issues/3222.

### Modifications:

Added conformance to `ChannelError` and wrote error messages for all
cases.

Added conformance to `NIOConnectionError`.

---------

Co-authored-by: George Barnett <gbarnett@apple.com>
2025-05-07 10:40:46 +00:00
Cory Benfield abe4f1bcb6 Replace almost all public static lets with computed vars (#3229)
Motivation:

Public static lets can serve a bunch of roles, but one of them is to
store simple constants: integers, and other trivial types, for example.
This is a nice pattern and for internal and private static lets it works
well, but for public ones it produces some inefficient code.

In particular, it has two downsides. First, it allocates storage for
that value. We don't actually need to allocate a few hundred extra
megabytes for the various integers we want to store.

Secondly, it forces calling code to access the address and call the
dispatch_once code in order to get hold of the value. For trivial types
we don't need that cost: they can just know what the value is directly.

Inlinable computed vars avoid all of these costs: they have no size
overhead for storage, and they are visible to all clients so their
values can be directly assembled.

While I'm here, I added a bunch of other inlinable annotations for a few
trivial data types I stumbled onto.

Modifications:

- Added loads of inlinables. Like, loads.
- Swapped many static lets to static vars.

Result:

Better codegen, smaller memory footprints, more attributes.
2025-05-02 16:08:10 +01:00
Cory Benfield 0f54d58bb5 Fix compiler issues on 5.10 x86 Ubuntu Noble. (#3224)
Motivation:

There's a known compiler issue on the 5.10 toolchain for x86 on Ubuntu
Noble. This issue causes the compile to fail, even though the code is
fine. We shouldn't allow that.

Modifications:

Shuffle the whitespace around to fix the issue.
Suppress the linter issues.

Result:

Compiler is back. Resolves #3223.
2025-04-28 10:07:35 +00:00
Raghav Roy 8440498328 Add More Peek API Variants for ByteBuffer (#3174)
### Motivation:

Existing get APIs require passing an explicit index and can be misused,
leading to verbose and error-prone code. Adding peek variants that
automatically use the current readerIndex improves safety and clarity.
This aims to address issue #2034 and issue #2736, and is a continuation
of PR #3157

### Modifications:

Introduced peekSlice(), peekLengthPrefixedSlice(), peekData(),
peekUUIDBytes() and peekWebSocketErrorCode().
Added tests for each peek API covering normal, empty and repeated peek
scenarios.

### Result:

Developers can now use nonmutating peek APIs to inspect ByteBuffer
contents without altering the reader index.
2025-04-10 14:44:53 +00:00
Raghav RoyandCory Benfield 12d8a4c6d7 Add Peek API for Multiple Integers (#3175)
### Motivation:

The current readMultipleIntegers methods are used to consume multiple
integer values at once, but lack an equivalent nonmutating API. This can
lead to unnecessary complexity when users want to inspect values without
advancing readerIndex. THis patch introduces peekMultipleIntegers which
uses the current readerIndex, improving safety. This extends previous
work on peek methods (issue #2034, issue #2736).

### Modifications:

Updated the generation script (.sh file) to produce peekMultipleIntegers
variants for each arity of readMultipleIntegers.
    Added new tests mirroring the existing multi-read/write tests

### Result:

Users can now inspect multiple integer values in a ByteBuffer without
consuming them, enabling safer workflows.

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
2025-04-10 10:23:27 +00:00
George BarnettandCory Benfield 69e8d39aa4 Expose the event loop from the loop bound boxes (#3179)
Motivation:

NIOLoopBound and NIOLoopBoundBox both have a public-but-underscored
event loop property, i.e. the loop to which the value is bound. It's
often very helpful to be able to access the event loop the value is
isolated to. Having access allows you to execute onto the event loop and
safely access the value.

Modifications:

- Make the property public and add a deprecated shim for the
public-but-underscored variant.

Result:

Can access the event loop of a loop bound value

Co-authored-by: Cory Benfield <lukasa@apple.com>
2025-04-09 13:47:34 +00:00
Raghav Roy 1d7a94655f Add Peek API variants for ByteBuffer (#3160)
### Motivation:
Existing get APIs require passing an explicit index and can be misused,
leading to verbose and error-prone code. Adding peek variants that
automatically use the current readerIndex improves safety and clarity.
This aims to address https://github.com/apple/swift-nio/issues/2034 and
https://github.com/apple/swift-nio/issues/2736, and is a continuation of
PR https://github.com/apple/swift-nio/pull/3157

### Modifications:
- Introduced peekBytes(), peekString(), peekNullTerminatedString(),
peekUTF8ValidatedString() and peekDispatchData().
- Added tests for each peek API covering normal, empty, repeated, and
partial read scenarios.

### Result:
Developers can now use nonmutating peek APIs to inspect ByteBuffer
contents without altering the reader index.

***PS**: I have focussed on the ByteBuffer-aux get\* implementations, so
I'm not sure if I am missing any other important/error-prone get\*
elsewhere, if so, please point me to them and I'll be happy to add
respective peek\*'s!*
2025-03-31 10:30:37 +01:00
Raghav RoyandGeorge Barnett e8260eb721 Add peekInteger API to ByteBuffer (#3157)
### Motivation:

The existing getInteger API is often used incorrectly, leading to
verbose or error-prone code as mentioned in
https://github.com/apple/swift-nio/issues/2034 and
https://github.com/apple/swift-nio/issues/2736. Users may
unintentionally access data without correctly managing the reader index.
To address this, I added a peekInteger API that reads integers using the
current readerIndex without modifying it.

### Modifications:

* Added a peekInteger method to ByteBuffer, which provides a nonmutating
way to read integers using the current readerIndex.
* Implemented peekInteger using the existing getInteger function.
* Added comprehensive unit tests to validate correct behavior, including
scenarios for different integer types, insufficient bytes, and
multi-write scenarios.

### Result:

* Users now have access to a safer API for inspecting integers in a
buffer without modifying state.
* Added tests for integer reading scenarios.

---------

Co-authored-by: George Barnett <gbarnett@apple.com>
2025-03-27 09:54:07 +00:00
scottmarchantandScott Marchant 320fe4c406 fix: Fix NIOCore build for wasm targets (#3156)
Fixes NIOCore compiler errors for the `wasm32` architecture.

### Motivation:

When compiling NIOCore for a SwiftWasm target, several compilation
errors such as the following occur:

```
> swift build --swift-sdk wasm32-unknown-wasi --target NIOCore

.../swift-nio/Sources/NIOCore/FileHandle.swift:151:42: error: cannot find type 'TwoUInt32s' in scope
149 | public final class NIOFileHandle: FileDescriptor & Sendable {
150 |     private static let descriptorClosed: CInt = CInt.min
151 |     private let descriptor: UnsafeAtomic<TwoUInt32s>
    |                                          `- error: cannot find type 'TwoUInt32s' in scope
152 | 
153 |     public var isOpen: Bool {
.../swift-nio/Sources/NIOCore/FileHandle.swift:77:8: error: Unknown architecture
 75 | typealias TwoUInt32s = DoubleWord
 76 | #else
 77 | #error("Unknown architecture")
    |        `- error: Unknown architecture
 78 | #endif
 79 | 
 
…
```
The compilation errors were introduced with the following change: 


https://github.com/apple/swift-nio/pull/2598/files#diff-a041d0c0d50a8f4fcda2020eeb4450ea994920ef61653cc06014457ccdb3ba0cR70

### Modifications:

The fix is straight-forward and unlikely to affect any existing
compilation targets other than the `wasm32` target.

We simply need to add `arch(wasm32)` to compiler architecture condtions
for a new typedef on line, then NIOCore compiles to wasm32 again.

### Result:

Before: NIOCore wasm build fails ❌ 

After: NIOCore wasm build succeeds ✅

Co-authored-by: Scott Marchant <scottm@passivelogic.com>
2025-03-27 09:28:30 +00:00
Rafael CepedaandFranz Busch 050158c75a Changed NIOAsyncChannel.executeThenClose to accept actor-isolated parameter (#3121)
Improve usability of NIOAsyncChannel.executeThenClose function from an
Actor

### Motivation:

When calling executeThenClose from inside an actor, the closure which we
pass is not isolated to the same actor
This makes it hard to use

e.g. the following code won’t compile on Swift 6 because the closure is
`self-isolated` so can’t be passed

```
await withDiscardingTaskGroup { group in
            do {
                try await serverChannel.executeThenClose { inboundStream, _ in
                    try await self.handleInboundStream(inboundStream: inboundStream, group: &group)
                }
             } catch {}
}
```

Making the closure as @Sendable allows it to be passed, but then we
can’t access `group` anymore

### Modifications:

Added actor isolation parameter to the `executeThenClose` function. 

### Result:

`executeThenClose` will be able to be asynchronously called from inside
an Actor, as it will now be part of the Actor's isolation domain.

---------

Co-authored-by: Franz Busch <privat@franz-busch.de>
2025-03-25 13:31:39 +00:00
Johannes Weiss 40ee44c6b9 always @preconcurrency import Glibc/Musl/Android/Bionic/WASILibc (#3153)
### Motivation:

The non-`Darwin` libcs don't have the correct concurrency annotations.
But due to these Swift bugs, it's important that the _first_ importer
uses `@preconcurrency`:

- https://github.com/swiftlang/swift/issues/79414
- https://github.com/swiftlang/swift/issues/77866

### Modifications:

Much like the Foundation (& corelibs) PRs such as
https://github.com/swiftlang/swift-foundation/pull/1175 , use
`@preconcurrency import` for the non-`Darwin` libcs.

### Result:

Fewer bad warnings/errors in user code.
2025-03-21 15:35:05 +00:00