Skip to content

Commit c9e2ac1

Browse files
authored
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.
1 parent d24d9ab commit c9e2ac1

File tree

15 files changed

+123
-51
lines changed

15 files changed

+123
-51
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"mallocCountTotal" : 108
2+
"mallocCountTotal": 108
33
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"mallocCountTotal" : 164376
3-
}
2+
"mallocCountTotal": 82500
3+
}
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,47 @@
11
{
2-
"10000000_asyncsequenceproducer": 19,
3-
"1000000_asyncwriter": 1000050,
4-
"1000_addHandlers": 44050,
2+
"1_reqs_1000_conn": 384050,
53
"1000_addHandlers_sync": 37050,
4+
"1000_addHandlers": 44050,
65
"1000_addRemoveHandlers_handlercontext": 8050,
76
"1000_addRemoveHandlers_handlername": 8050,
87
"1000_addRemoveHandlers_handlertype": 8050,
9-
"1000_autoReadGetAndSet": 18050,
108
"1000_autoReadGetAndSet_sync": 0,
9+
"1000_autoReadGetAndSet": 18050,
1110
"1000_copying_bytebufferview_to_array": 1050,
1211
"1000_copying_circularbuffer_to_array": 1050,
13-
"1000_getHandlers": 8050,
1412
"1000_getHandlers_sync": 35,
13+
"1000_getHandlers": 8050,
1514
"1000_reqs_1_conn": 26400,
1615
"1000_rst_connections": 145050,
1716
"1000_tcpbootstraps": 3050,
1817
"1000_tcpconnections": 152050,
1918
"1000_udp_reqs": 6050,
2019
"1000_udpbootstraps": 2050,
2120
"1000_udpconnections": 75050,
22-
"1_reqs_1000_conn": 384050,
21+
"1000000_asyncwriter": 1000050,
22+
"10000000_asyncsequenceproducer": 20,
2323
"assume_isolated_scheduling_10000_executions": 89,
2424
"bytebuffer_lots_of_rw": 2050,
2525
"creating_10000_headers": 0,
2626
"decode_1000_ws_frames": 2050,
27-
"encode_1000_ws_frames_holding_buffer": 3,
2827
"encode_1000_ws_frames_holding_buffer_with_mask": 2050,
29-
"encode_1000_ws_frames_holding_buffer_with_space": 3,
3028
"encode_1000_ws_frames_holding_buffer_with_space_with_mask": 2050,
31-
"encode_1000_ws_frames_new_buffer": 3050,
29+
"encode_1000_ws_frames_holding_buffer_with_space": 3,
30+
"encode_1000_ws_frames_holding_buffer": 3,
3231
"encode_1000_ws_frames_new_buffer_with_mask": 5050,
33-
"encode_1000_ws_frames_new_buffer_with_space": 3050,
3432
"encode_1000_ws_frames_new_buffer_with_space_with_mask": 5050,
33+
"encode_1000_ws_frames_new_buffer_with_space": 3050,
34+
"encode_1000_ws_frames_new_buffer": 3050,
3535
"execute_hop_10000_tasks": 0,
3636
"flat_schedule_10000_tasks": 100100,
3737
"flat_schedule_assume_isolated_10000_tasks": 80100,
3838
"future_assume_isolated_lots_of_callbacks": 74050,
3939
"future_erase_result": 4050,
4040
"future_lots_of_callbacks": 74050,
41-
"get_100000_headers_canonical_form": 500050,
42-
"get_100000_headers_canonical_form_trimming_whitespace": 500050,
4341
"get_100000_headers_canonical_form_trimming_whitespace_from_long_string": 500050,
4442
"get_100000_headers_canonical_form_trimming_whitespace_from_short_string": 500050,
43+
"get_100000_headers_canonical_form_trimming_whitespace": 500050,
44+
"get_100000_headers_canonical_form": 500050,
4545
"modifying_1000_circular_buffer_elements": 0,
4646
"modifying_byte_buffer_view": 6050,
4747
"ping_pong_1000_reqs_1_conn": 314,
@@ -54,6 +54,6 @@
5454
"scheduling_10000_executions": 89,
5555
"submit_10000_tasks": 20100,
5656
"submit_assume_isolated_10000_tasks": 20100,
57-
"udp_1000_reqs_1_conn": 6200,
58-
"udp_1_reqs_1000_conn": 162050
57+
"udp_1_reqs_1000_conn": 162050,
58+
"udp_1000_reqs_1_conn": 6200
5959
}
Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,47 @@
11
{
2-
"10000000_asyncsequenceproducer": 19,
3-
"1000000_asyncwriter": 1000050,
4-
"1000_addHandlers": 44050,
2+
"1_reqs_1000_conn": 384000,
53
"1000_addHandlers_sync": 37050,
4+
"1000_addHandlers": 44050,
65
"1000_addRemoveHandlers_handlercontext": 8050,
76
"1000_addRemoveHandlers_handlername": 8050,
87
"1000_addRemoveHandlers_handlertype": 8050,
9-
"1000_autoReadGetAndSet": 18050,
108
"1000_autoReadGetAndSet_sync": 0,
9+
"1000_autoReadGetAndSet": 18050,
1110
"1000_copying_bytebufferview_to_array": 1050,
1211
"1000_copying_circularbuffer_to_array": 1050,
13-
"1000_getHandlers": 8050,
1412
"1000_getHandlers_sync": 35,
13+
"1000_getHandlers": 8050,
1514
"1000_reqs_1_conn": 26400,
1615
"1000_rst_connections": 145050,
1716
"1000_tcpbootstraps": 3050,
1817
"1000_tcpconnections": 152050,
1918
"1000_udp_reqs": 6050,
2019
"1000_udpbootstraps": 2050,
2120
"1000_udpconnections": 75050,
22-
"1_reqs_1000_conn": 384050,
21+
"1000000_asyncwriter": 1000050,
22+
"10000000_asyncsequenceproducer": 20,
2323
"assume_isolated_scheduling_10000_executions": 89,
2424
"bytebuffer_lots_of_rw": 2050,
2525
"creating_10000_headers": 0,
2626
"decode_1000_ws_frames": 2050,
27-
"encode_1000_ws_frames_holding_buffer": 3,
2827
"encode_1000_ws_frames_holding_buffer_with_mask": 2050,
29-
"encode_1000_ws_frames_holding_buffer_with_space": 3,
3028
"encode_1000_ws_frames_holding_buffer_with_space_with_mask": 2050,
31-
"encode_1000_ws_frames_new_buffer": 3050,
29+
"encode_1000_ws_frames_holding_buffer_with_space": 3,
30+
"encode_1000_ws_frames_holding_buffer": 3,
3231
"encode_1000_ws_frames_new_buffer_with_mask": 5050,
33-
"encode_1000_ws_frames_new_buffer_with_space": 3050,
3432
"encode_1000_ws_frames_new_buffer_with_space_with_mask": 5050,
33+
"encode_1000_ws_frames_new_buffer_with_space": 3050,
34+
"encode_1000_ws_frames_new_buffer": 3050,
3535
"execute_hop_10000_tasks": 0,
3636
"flat_schedule_10000_tasks": 100100,
37-
"flat_schedule_assume_isolated_10000_tasks": 90100,
37+
"flat_schedule_assume_isolated_10000_tasks": 80100,
3838
"future_assume_isolated_lots_of_callbacks": 74050,
3939
"future_erase_result": 4050,
4040
"future_lots_of_callbacks": 74050,
41-
"get_100000_headers_canonical_form": 700050,
42-
"get_100000_headers_canonical_form_trimming_whitespace": 700050,
43-
"get_100000_headers_canonical_form_trimming_whitespace_from_long_string": 700050,
44-
"get_100000_headers_canonical_form_trimming_whitespace_from_short_string": 700050,
41+
"get_100000_headers_canonical_form_trimming_whitespace_from_long_string": 500050,
42+
"get_100000_headers_canonical_form_trimming_whitespace_from_short_string": 500050,
43+
"get_100000_headers_canonical_form_trimming_whitespace": 500050,
44+
"get_100000_headers_canonical_form": 500050,
4545
"modifying_1000_circular_buffer_elements": 0,
4646
"modifying_byte_buffer_view": 6050,
4747
"ping_pong_1000_reqs_1_conn": 314,
@@ -54,6 +54,6 @@
5454
"scheduling_10000_executions": 89,
5555
"submit_10000_tasks": 20100,
5656
"submit_assume_isolated_10000_tasks": 20100,
57-
"udp_1000_reqs_1_conn": 6200,
58-
"udp_1_reqs_1000_conn": 162050
59-
}
57+
"udp_1_reqs_1000_conn": 162050,
58+
"udp_1000_reqs_1_conn": 6200
59+
}

Sources/NIOCore/AsyncAwaitSupport.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,10 @@ extension ChannelPipeline {
280280
"ChannelHandlerContext is not Sendable and it is therefore not safe to be used outside of its EventLoop"
281281
)
282282
@inlinable
283-
public func context<Handler: ChannelHandler>(handlerType: Handler.Type) async throws -> ChannelHandlerContext {
283+
@preconcurrency
284+
public func context<Handler: ChannelHandler & _NIOCoreSendableMetatype>(
285+
handlerType: Handler.Type
286+
) async throws -> ChannelHandlerContext {
284287
try await self.context(handlerType: handlerType).map { UnsafeTransfer($0) }.get().wrappedValue
285288
}
286289

Sources/NIOCore/ChannelPipeline.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,10 @@ public final class ChannelPipeline: ChannelInvoker {
534534
/// - handlerType: The type of the handler to search for.
535535
/// - Returns: the `EventLoopFuture` which will be notified once the the operation completes.
536536
@inlinable
537-
public func context<Handler: ChannelHandler>(handlerType: Handler.Type) -> EventLoopFuture<ChannelHandlerContext> {
537+
@preconcurrency
538+
public func context<Handler: ChannelHandler & _NIOCoreSendableMetatype>(
539+
handlerType: Handler.Type
540+
) -> EventLoopFuture<ChannelHandlerContext> {
538541
let promise = self.eventLoop.makePromise(of: ChannelHandlerContext.self)
539542

540543
if self.eventLoop.inEventLoop {
@@ -555,7 +558,10 @@ public final class ChannelPipeline: ChannelInvoker {
555558
/// - Returns: An ``EventLoopFuture`` that is succeeded if a handler of the given type is contained in the pipeline. Otherwise
556559
/// the future will be failed with an error.
557560
@inlinable
558-
public func containsHandler<Handler: ChannelHandler>(type: Handler.Type) -> EventLoopFuture<Void> {
561+
@preconcurrency
562+
public func containsHandler<Handler: ChannelHandler & _NIOCoreSendableMetatype>(
563+
type: Handler.Type
564+
) -> EventLoopFuture<Void> {
559565
self.handler(type: type).map { _ in () }
560566
}
561567

@@ -2424,7 +2430,10 @@ extension ChannelPipeline: CustomDebugStringConvertible {
24242430
/// - Parameters:
24252431
/// - type: the type of `ChannelHandler` to return.
24262432
@inlinable
2427-
public func handler<Handler: ChannelHandler>(type _: Handler.Type) -> EventLoopFuture<Handler> {
2433+
@preconcurrency
2434+
public func handler<Handler: ChannelHandler & _NIOCoreSendableMetatype>(
2435+
type _: Handler.Type
2436+
) -> EventLoopFuture<Handler> {
24282437
self.context(handlerType: Handler.self).map { context in
24292438
guard let typedContext = context.handler as? Handler else {
24302439
preconditionFailure(
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftNIO open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the SwiftNIO project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#if compiler(>=6.2)
16+
public typealias _NIOCoreSendableMetatype = SendableMetatype
17+
#else
18+
public typealias _NIOCoreSendableMetatype = Any
19+
#endif

Sources/NIOFileSystem/DirectoryEntries.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ public struct DirectoryEntries: AsyncSequence, Sendable {
3636
/// Creates a ``DirectoryEntries`` sequence by wrapping an `AsyncSequence` of _batches_ of
3737
/// directory entries.
3838
@preconcurrency
39-
public init<S: AsyncSequence & Sendable>(wrapping sequence: S) where S.Element == Batched.Element {
39+
public init<S: AsyncSequence & Sendable>(wrapping sequence: S)
40+
where S.Element == Batched.Element, S.AsyncIterator: _NIOFileSystemSendableMetatype {
4041
self.batchedSequence = Batched(wrapping: sequence)
4142
}
4243

@@ -95,7 +96,8 @@ extension DirectoryEntries {
9596
/// Creates a ``DirectoryEntries/Batched`` sequence by wrapping an `AsyncSequence`
9697
/// of directory entry batches.
9798
@preconcurrency
98-
public init<S: AsyncSequence & Sendable>(wrapping sequence: S) where S.Element == Element {
99+
public init<S: AsyncSequence & Sendable>(wrapping sequence: S)
100+
where S.Element == Element, S.AsyncIterator: _NIOFileSystemSendableMetatype {
99101
self.stream = BufferedOrAnyStream<[DirectoryEntry], DirectoryEntryProducer>(wrapping: sequence)
100102
}
101103

Sources/NIOFileSystem/FileChunks.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ public struct FileChunks: AsyncSequence, Sendable {
3131
private let stream: BufferedOrAnyStream<ByteBuffer, FileChunkProducer>
3232

3333
/// Create a ``FileChunks`` sequence backed by wrapping an `AsyncSequence`.
34-
public init<S: AsyncSequence & Sendable>(wrapping sequence: S) where S.Element == ByteBuffer {
34+
@preconcurrency
35+
public init<S: AsyncSequence & Sendable>(wrapping sequence: S)
36+
where S.Element == ByteBuffer, S.AsyncIterator: _NIOFileSystemSendableMetatype {
3537
self.stream = BufferedOrAnyStream(wrapping: sequence)
3638
}
3739

Sources/NIOFileSystem/Internal/BufferedOrAnyStream.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ internal enum BufferedOrAnyStream<Element: Sendable, Delegate: NIOAsyncSequenceP
2828
self = .nioThrowingAsyncSequenceProducer(stream)
2929
}
3030

31-
internal init<S: AsyncSequence & Sendable>(wrapping stream: S) where S.Element == Element {
31+
internal init<S: AsyncSequence & Sendable>(wrapping stream: S)
32+
where S.Element == Element, S.AsyncIterator: _NIOFileSystemSendableMetatype {
3233
self = .anyAsyncSequence(AnyAsyncSequence(wrapping: stream))
3334
}
3435

@@ -72,7 +73,8 @@ internal enum BufferedOrAnyStream<Element: Sendable, Delegate: NIOAsyncSequenceP
7273
internal struct AnyAsyncSequence<Element>: AsyncSequence, Sendable {
7374
private let _makeAsyncIterator: @Sendable () -> AsyncIterator
7475

75-
internal init<S: AsyncSequence & Sendable>(wrapping sequence: S) where S.Element == Element {
76+
internal init<S: AsyncSequence & Sendable>(wrapping sequence: S)
77+
where S.Element == Element, S.AsyncIterator: _NIOFileSystemSendableMetatype {
7678
self._makeAsyncIterator = {
7779
AsyncIterator(wrapping: sequence.makeAsyncIterator())
7880
}
@@ -82,7 +84,7 @@ internal struct AnyAsyncSequence<Element>: AsyncSequence, Sendable {
8284
self._makeAsyncIterator()
8385
}
8486

85-
internal struct AsyncIterator: AsyncIteratorProtocol {
87+
internal struct AsyncIterator: AsyncIteratorProtocol, _NIOFileSystemSendableMetatype {
8688
private var iterator: any AsyncIteratorProtocol
8789

8890
init<I: AsyncIteratorProtocol>(wrapping iterator: I) where I.Element == Element {

0 commit comments

Comments
 (0)