Fix Swift for WebAssembly compilation in NIOFoundationCompat.
### Motivation:
NIO is a common dependency, and it is important to enable compiling NIO
using Swift for WebAssembly. This PR fixes compilation for
NIOFoundationCompat.
### Modifications:
- Fix NIOFoundationCompat compilation
### Result:
With these changes, the following build commands succeed: ✅
```
swift build --swift-sdk wasm32-unknown-wasip1-threads --target NIOCore
swift build --swift-sdk wasm32-unknown-wasip1-threads --target NIOFoundationCompat
```
### Context:
This PR is [part of a larger effort by
PassiveLogic](https://github.com/PassiveLogic/swift-web-examples/issues/1)
to improve Swift for WebAssembly support
### 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.
### Motivation:
Warnings are annoying.
### Modifications:
- Remove unnecessary use of `Foundation.Thread` which isn't Sendable.
- Remove now unnecessary `@retroactive`s.
- Enable `-warnings-as-errors` in CI
### Result:
- Warnings can't sneak in as easily anymore
- No more warnings left in `swift-nio`
```
$ rm -rf .build/arm64-apple-macosx/ && swift build --build-tests -Xswiftc -warnings-as-errors > /dev/null
echo $?
$ echo $?
0
```
Co-authored-by: Cory Benfield <lukasa@apple.com>
Motivation:
When getting a `Data` from a `ByteBuffer` we currently allocate twice
(`__DataStorage`) and the closure for `Data.Deallocator`.
Modifications:
We can optimise that by making the closure capture exactly one
`AnyObject` which is already a reference counted object. The compiler
realises that (on Linux) and saves us an alloc.
Thanks @lukasa for the suggestion here:
https://github.com/apple/swift-nio/pull/1836#issuecomment-830044155
Result:
Fewer allocs.
### Motivation:
In some (probably niche) scenarios, especially in pre-Concurrency UI
applications on Darwin, it can be useful to wait for an a value whilst
still running the current `RunLoop`. That allows the UI and other things
to work whilst we're waiting for a future to complete.
### Modifications:
- Add `NIOFoundationCompat.EventLoopFuture.waitSpinningRunLoop()`.
### Result:
Better compatibility with Cocoa.
### Motivation:
Documentation checking catches more issues in Swift 6.0.
### Modifications:
Adopt the Swift 6.0 image and fix the errors.
### Result:
More accurate docs.
* 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.
Motivation:
`hasFeature(RetroactiveAttribute)` doesn't work as expected, but
`$RetroactiveAttribute` does.
Modifications:
Switch from `hasFeature` to `$RetroactiveAttribute`.
Result:
- `@retroactive` is applied appropriately
Motivation:
We should use the more granular guard for uses of @retroactive rather
than coarse swift versions to guard against corner-cases
Modifications:
Switch `#if compiler(>=5.11)` for `#if hasFeature(RetroactiveAttribute)`
Result:
No change in most cases, more protected against corner-cases.
Motivation:
In nightly Swift, we now need to mark retroactive conformances when
they are intentional. These conformances are safe for us, so we can
safely suppress the warnings.
Modifications:
- Mark NIOFoundationCompat retroactive conformances.
Result:
Nightly builds work again
Motivation:
UUIDs are often sent over the wire but writing and reading their bytes
to/from a buffer is a bit of a pain.
Modifications:
- Add utilties to 'NIOFoundationCompat' for reading/writing and
getting/setting a UUID on a `ByteBuffer`.
Result:
Easier to write/read UUIDs to/from a buffer.
Co-authored-by: Cory Benfield <lukasa@apple.com>
Motivation:
As we've largely completed our move to split out our core abstractions,
we now have an opportunity to clean up our dependencies and imports. We
should arrange for everything to only import NIO if it actually needs
it, and to correctly express dependencies on NIOCore and NIOEmbedded
where they exist.
We aren't yet splitting out tests that only test functionality in
NIOCore, that will follow in a separate patch.
Modifications:
- Fixed up imports
- Made sure our protocols only require NIOCore.
Result:
Better expression of dependencies.
Co-authored-by: George Barnett <gbarnett@apple.com>
Motivation:
Issue for #1891 to add JSONSerialization in NIOFoundationCompat.
Modifications:
Adds:
JSONSerialization+ByteBuffer.swift
JSONSerialization+ByteBufferTest.swift
JSONSerialization+ByteBufferTest+XCTest.swift
Result:
Support for transforming byteBuffer data to a Foundation object.
Co-authored-by: Cory Benfield <lukasa@apple.com>
Motivation:
Per SR-10219, Data does not implement withContiguousStorageWithAvailable
and the maintainers do not believe it can. This forces code that writes
Data into ByteBuffers into slow-paths. Given that Data conforms to
ContiguousBytes and DataProtocol, we can arrange to serve a number of
use-cases by providing fast paths for all conforming types. This makes
it easier to use types vended by other Foundation-using libraries, such
as Swift Crypto.
Modifications:
- Implement `writeContiguousBytes` and `setContiguousBytes`.
- Implement `writeData` and `setData` for `DataProtocol` implementations
Result:
Better support for writing `Data` and friends into `ByteBuffer`s.
Motivation:
There are multiple sub-optimal ByteBuffer creation patterns that occur
in the wild. Most often they happen when people don't actually have
access to a `Channel` just want to "convert" a `String` into a
`ByteBuffer`. To do this, they are forced to type
var buffer = ByteBufferAllocator().buffer(capacity: string.utf8.count)
buffer.writeString(string)
Sometimes, they don't get the capacity calculation right or just put a
`0`.
Similar problems happen if NIO users want to cache a ByteBuffer in their
`ChannelHandler`. You will then find this code:
```swift
if self.buffer == nil {
self.buffer = receivedBuffer
} else {
var receivedBuffer = receivedBuffer
self.buffer!.writeBuffer(&receivedBuffer)
}
```
And lastly, sometimes people want to append one `ByteBuffer` to another
without mutating the appendee. That's also cumbersome because we only
support a mutable version of `writeBuffer`.
Modifications:
- add `ByteBuffer` convenience initialisers
- add convenience `writeBuffer` methods to `Optional<ByteBuffer>`
- add `writeBufferImmutable` which doesn't mutate the appendee.
Result:
More convenience.
Co-authored-by: Cory Benfield <lukasa@apple.com>
Co-authored-by: Cory Benfield <lukasa@apple.com>
Motivation:
ByteBufferView isn't a mutable collection, but it probably should be.
Modifications:
- Add `copyBytes(at:to:length)` to `ByteBuffer` to copy bytes from a
readable region of a buffer to another part of the buffer
- Conform `ByteBufferView` to `MutableCollection`, `RangeReplaceableCollection`
and `MutableDataProtocol`
- Add an allocation counting test
Result:
`ByteBufferView` is now mutable.
Motivation:
ByteBuffer.readJSONDecodable just ignored the JSONDecoder that got
passed in.
Modifications:
Pass through the JSONDecoder that was specified.
Result:
Respect the user's choices.
Motivation:
JSONDecoder settings should be respected but were not.
Modifications:
This allows actually configuring the `JSONDecoder` instead of being stuck with the defaults.
Result:
Settings respected.
Motivation:
So far, it has been harder than necessary to use Codable & ByteBuffer.
These new APIs should simplify that and allow future optimisations.
Modifications:
Add new API to use `JSONEncoder` and `JSONDecoder` directly with
`ByteBuffer`.
Result:
Easier Codable + ByteBuffer usage.
Motivation:
Previously, ByteBuffer tried to never copy the bytes when transferring
to a `Data`. For small copies that's definitely not a good choice
because it means an extra allocation.
Modifications:
- introduce `ByteTransferStrategy` so the user can choose
- make a heuristic: copy is less than 256kB, try not to copy above
Result:
More sensible defaults.
Motivation:
ByteBufferView should conform to DataProtocol.
Modifications:
Conform ByteBufferView to DataProtocol.
Result:
ByteBufferView conforms to DataProtocol.
Motivation:
For historic reasons, the get* implementations checked the same indices
repeatedly and the checks were also repetitive.
Modifications:
unify and de-deplicate get* range checks
Result:
fixes#884
Motivation:
Previously, ByteBuffers get* methods would get bytes from anywhere, even
if the bytes were not readable. That can lead to security issues in code
that doesn't expect this. NIO shouldn't contain such unsafe methods
without the word 'unsafe'.
Modifications:
Made all `get*` methods respect reader/writerIndex.
Result:
safer user code
Motivation:
- Foundation has (on master) introduces a ContiguousBytes protocol and we
should conform to that.
- Sequence has withContiguousStorageIfAvailable and ByteBufferView
should conform to that too
Modifications:
add conformance
Result:
more compatibility.
Motivation:
ByteBuffer methods like `set(string:)` never felt very Swift-like and
also didn't look the same as their counterparts like `getString(...)`.
Modifications:
- rename all `ByteBuffer.set/write(<type>:,...)` methods to
`ByteBuffer.set/write<Type>(...)`
- polyfill the old spellings in `_NIO1APIShims`
Result:
code more Swift-like
Motivation:
ContiguousCollection is no longer necessary because Sequence gained
withContiguousStorageIfAvailable.
Modifications:
Removed ContiguousCollection and switch to withContiguousStorageIfAvailable.
Result:
less code
Motivation:
ByteBuffer has pretty good string writing APIs, but they're imperfect.
In particular, the methods in ByteBuffer-aux both return optional Int,
which is strange as they cannot fail. We also only have support for writing
strings in UTF-8.
Modifications:
- ByteBuffer.set(string:at:) and ByteBuffer.write(string:) now both
return `Int`, and their return value has been made discardable.
- NIOFoundationCompat has been expanded with two new methods for writing
strings to ByteBuffers in various encodings using Foundation's
encoding support: ByteBuffer.set(string:encoding:at:) and
ByteBuffer.write(string:encoding:).
- NIOFoundationCompat has also been expanded with a companion to the
already existing ByteBuffer.getString(at:length:encoding), namely
ByteBuffer.readString(length:encoding:).
- New error enum for reporting failures to encode.
Result:
Easier to work with strings in a wider variety of cases with
ByteBuffer
Resolves#253.
Motivation:
NIO2 development starts now.
Modifications:
Made NIO Swift 5-only for everything else see docs/public-api-changes-NIO1-to-NIO2.md
Result:
NIO2 development can start.
Motivation:
`ByteBuffer`'s `get*` methods can be used in an unsafe way and we didn't
warn the user enough.
Modifications:
Warn the user in the documentation of all the `get*` methods.
Result:
Less confusion.
Motivation:
@_inlineable is important for at least all performance sensitive
functions that use generics and/or closures.
Modifications:
added two missing @_inlineable
Result:
fewer allocations (not measurable because https://bugs.swift.org/browse/SR-7542)
Motivation:
We can cleanup the code by removing return keywords in closures sometimes.
Modifications:
Remove return when possible.
Result:
Cleaner code.
Motivation:
Sometimes we deviated from the style the Swift stdlib sets out for no
reason.
Modifications:
Fixed some stylistic deviations.
Result:
Looks more Swift-like.
Motivation:
Foundation is problematic for a few reasons:
- its implementation is different on Linux and on macOS which means our
macOS tests might be inaccurate
- on macOS it uses ObjC Foundation which means the autorelease pool
might get populated
- it links the world on Linux which means we can't do static
binaries at all
Modifications:
removed the last bits of Foundation dependency
Result:
no Foundation dependency