Skip to content

Commit ccc1b15

Browse files
fixup: Move this to ChannelCore and expose withUnsafeTransportIfAvailable via syncOperations
1 parent 2167148 commit ccc1b15

File tree

3 files changed

+35
-16
lines changed

3 files changed

+35
-16
lines changed

Sources/NIOCore/ChannelPipeline.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,6 +1605,29 @@ extension ChannelPipeline {
16051605
self.eventLoop.assertInEventLoop()
16061606
self._pipeline.triggerUserOutboundEvent0(event, promise: promise)
16071607
}
1608+
1609+
/// Provides scoped access to the underlying transport, if the channel supports it.
1610+
///
1611+
/// This is an advanced API for reading or manipulating the underlying transport that backs a channel. Users must
1612+
/// not close the transport or invalidate any invariants that NIO relies upon for the channel operation.
1613+
///
1614+
/// Not all channels support access to the underlying channel. If the channel does not support this API, the
1615+
/// closure is not called and this function immediately returns `nil`.
1616+
///
1617+
/// - Parameter body: A closure that takes the underlying transport, if the channel supports this operation.
1618+
/// - Returns: The value returned by the closure, or `nil` if the channel does not expose its transport.
1619+
/// - Throws: If the underlying transport is unavailable, or rethrows any error thrown by the closure.
1620+
@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *)
1621+
public func withUnsafeTransportIfAvailable<Transport, Result>(
1622+
of _: Transport.Type,
1623+
_ body: (_ transport: Transport) throws -> Result
1624+
) throws -> Result? {
1625+
self.eventLoop.assertInEventLoop()
1626+
guard let channel = self._pipeline._channel as? any NIOTransportAccessibleChannel<Transport> else {
1627+
return nil
1628+
}
1629+
return try channel.withUnsafeTransport(body)
1630+
}
16081631
}
16091632

16101633
/// Returns a view of operations which can be performed synchronously on this pipeline. All

Sources/NIOCore/NIOTransportAccessibleChannel.swift

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15-
/// A ``NIOTransportAccessibleChannel`` is a ``Channel`` that provides access to its underlying transport.
16-
public protocol NIOTransportAccessibleChannel<Transport>: Channel {
15+
/// A ``NIOTransportAccessibleChannel`` is a ``ChannelCore`` that provides access to its underlying transport.
16+
public protocol NIOTransportAccessibleChannel<Transport>: ChannelCore {
1717
/// The type of the underlying transport.
1818
associatedtype Transport
1919

@@ -23,21 +23,10 @@ public protocol NIOTransportAccessibleChannel<Transport>: Channel {
2323
/// not close the transport or invalidate any invariants that NIO relies upon for the channel operation.
2424
///
2525
/// Not all channels are expected to conform to ``NIOTransportAccessibleChannel``, but this can be determined at
26-
/// runtime:
26+
/// runtime.
2727
///
28-
/// ```swift
29-
/// if let channel = channel as? any NIOTransportAccessibleChannel {
30-
/// channel.withUnsafeTransport { transport in /* Do something with untyped transport. */ }
31-
/// }
32-
/// ```
33-
///
34-
/// When you expect a specific associated transport type, get a typed transport closure:
35-
///
36-
/// ```swift
37-
/// if let channel = channel as? any NIOTransportAccessibleChannel<NIOBSDSocket.Handle>) {
38-
/// channel.withUnsafeTransport { transport in /* Do something with typed transport. */ }
39-
/// }
40-
/// ```
28+
/// Users should not attempt to use this API direcly, but should instead use
29+
/// ``ChannelPipeline/SynchronousOperations/withUnsafeTransportIfAvailable(of:_:)``.
4130
///
4231
/// - Parameter body: A closure that takes the underlying transport.
4332
/// - Returns: The value returned by the closure.

Tests/NIOPosixTests/NIOTransportAccessibleChannelTests.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,12 @@ import Testing
4646
#expect(fd__ == fd_)
4747
}
4848
}
49+
50+
// But this is how we want people to use the API -- via sync operations.
51+
try channel.eventLoop.submit {
52+
try channel.pipeline.syncOperations.withUnsafeTransportIfAvailable(of: NIOBSDSocket.Handle.self) { transport in
53+
#expect(type(of: transport) == NIOBSDSocket.Handle.self)
54+
}
55+
}.wait()
4956
}
5057
}

0 commit comments

Comments
 (0)