Repository: apple/swift-nio
File: Sources/NIOCore/Channel.swift (Swift)

Code before:
    func channelRead0(_ data: NIOAny)

    /// Called when an inbound error was encountered but was not consumed by any `ChannelInboundHandler` in the `ChannelPipeline`.
    ///
    /// - Parameters:
    ///   - error: The `Error` that was encountered.
    func errorCaught0(error: Error)
}

/// A `Channel` is easiest thought of as a network socket. But it can be anything that is capable of I/O operations such
/// as read, write, connect, and bind.
///
/// - Note: All operations on `Channel` are thread-safe.
///
/// In SwiftNIO, all I/O operations are asynchronous and hence all operations on `Channel` are asynchronous too. This means
/// that all I/O operations will return immediately, usually before the work has been completed. The `EventLoopPromise`s
/// passed to or returned by the operations are used to retrieve the result of an operation after it has completed.
///
/// A `Channel` owns its `ChannelPipeline` which handles all I/O events and requests associated with the `Channel`.
public protocol Channel: AnyObject, ChannelOutboundInvoker, _NIOPreconcurrencySendable {
    /// The `Channel`'s `ByteBuffer` allocator. This is _the only_ supported way of allocating `ByteBuffer`s to be used with this `Channel`.
    var allocator: ByteBufferAllocator { get }

    /// The `closeFuture` will fire when the `Channel` has been closed.
    ///
    /// - Important: This future will never be failed, as it signals when the channel has been closed, and this action cannot fail.
    ///              If you are interested in any errors thrown during `close` to diagnose any unclean channel closures, you
    ///              should instead use the future returned from ``Channel/close(mode:file:line:)`` or pass a promise via
    ///              ``Channel/close(mode:promise:)``.
    var closeFuture: EventLoopFuture<Void> { get }

    /// The `ChannelPipeline` which handles all I/O events and requests associated with this `Channel`.
    var pipeline: ChannelPipeline { get }

    /// The local `SocketAddress`.
    var localAddress: SocketAddress? { get }

    /// The remote peer's `SocketAddress`.
    var remoteAddress: SocketAddress? { get }

    /// `Channel`s are hierarchical and might have a parent `Channel`. `Channel` hierarchies are in use for certain
    /// protocols such as HTTP/2.
    var parent: Channel? { get }

    /// Set `option` to `value` on this `Channel`.
    func setOption<Option: ChannelOption>(_ option: Option, value: Option.Value) -> EventLoopFuture<Void>

    /// Get the value of `option` for this `Channel`.
    func getOption<Option: ChannelOption>(_ option: Option) -> EventLoopFuture<Option.Value>

    /// Returns if this `Channel` is currently writable.

Review comment (bug):
It can absolutely fail if a `Channel` doesn't implement this as expected, which is quite likely given that this is the first time we're documenting it 😄

I think we should say this it _should_ never be failed.

Code after:
    func channelRead0(_ data: NIOAny)

    /// Called when an inbound error was encountered but was not consumed by any `ChannelInboundHandler` in the `ChannelPipeline`.
    ///
    /// - Parameters:
    ///   - error: The `Error` that was encountered.
    func errorCaught0(error: Error)
}

/// A `Channel` is easiest thought of as a network socket. But it can be anything that is capable of I/O operations such
/// as read, write, connect, and bind.
///
/// - Note: All operations on `Channel` are thread-safe.
///
/// In SwiftNIO, all I/O operations are asynchronous and hence all operations on `Channel` are asynchronous too. This means
/// that all I/O operations will return immediately, usually before the work has been completed. The `EventLoopPromise`s
/// passed to or returned by the operations are used to retrieve the result of an operation after it has completed.
///
/// A `Channel` owns its `ChannelPipeline` which handles all I/O events and requests associated with the `Channel`.
public protocol Channel: AnyObject, ChannelOutboundInvoker, _NIOPreconcurrencySendable {
    /// The `Channel`'s `ByteBuffer` allocator. This is _the only_ supported way of allocating `ByteBuffer`s to be used with this `Channel`.
    var allocator: ByteBufferAllocator { get }

    /// The `closeFuture` will fire when the `Channel` has been closed.
    ///
    /// - Important: This future should never be failed: it signals when the channel has been closed, and this action should not fail,
    ///              regardless of whether the close happenned cleanly or not.
    ///              If you are interested in any errors thrown during `close` to diagnose any unclean channel closures, you
    ///              should instead use the future returned from ``ChannelOutboundInvoker/close(mode:file:line:)-7hlgf``
    ///              or pass a promise via ``ChannelOutboundInvoker/close(mode:promise:)``.
    var closeFuture: EventLoopFuture<Void> { get }

    /// The `ChannelPipeline` which handles all I/O events and requests associated with this `Channel`.
    var pipeline: ChannelPipeline { get }

    /// The local `SocketAddress`.
    var localAddress: SocketAddress? { get }

    /// The remote peer's `SocketAddress`.
    var remoteAddress: SocketAddress? { get }

    /// `Channel`s are hierarchical and might have a parent `Channel`. `Channel` hierarchies are in use for certain
    /// protocols such as HTTP/2.
    var parent: Channel? { get }

    /// Set `option` to `value` on this `Channel`.
    func setOption<Option: ChannelOption>(_ option: Option, value: Option.Value) -> EventLoopFuture<Void>

    /// Get the value of `option` for this `Channel`.
    func getOption<Option: ChannelOption>(_ option: Option) -> EventLoopFuture<Option.Value>