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

Code before:
    /// - Important: After this method returned the underlying ``Channel`` will be closed.
    ///
    /// - Parameter body: A closure that gets scoped access to the inbound and outbound.
    public func executeThenClose<Result>(
        _ body: (_ inbound: NIOAsyncChannelInboundStream<Inbound>, _ outbound: NIOAsyncChannelOutboundWriter<Outbound>)
            async throws -> Result
    ) async throws -> Result {
        let result: Result
        do {
            result = try await body(self._inbound, self._outbound)
        } catch let bodyError {
            do {
                self._outbound.finish()
                try await self.channel.close().get()
                throw bodyError
            } catch {
                throw bodyError
            }
        }

        self._outbound.finish()
        // We ignore errors from close, since all we care about is that the channel has been closed
        // at this point.
        self.channel.close(promise: nil)
        // `closeFuture` is never failed, so we can ignore the error
        try? await self.channel.closeFuture.get()

        return result
    }
}

// swift-format-ignore: AmbiguousTrailingClosureOverload
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
extension NIOAsyncChannel {
    /// Provides scoped access to the inbound side of the underlying ``Channel``.
    ///
    /// - Important: After this method returned the underlying ``Channel`` will be closed.
    ///
    /// - Parameter body: A closure that gets scoped access to the inbound.
    public func executeThenClose<Result>(
        _ body: (_ inbound: NIOAsyncChannelInboundStream<Inbound>) async throws -> Result
    ) async throws -> Result where Outbound == Never {
        try await self.executeThenClose { inbound, _ in
            try await body(inbound)
        }
    }
}

extension Channel {
    @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
    @inlinable

Review comment (suggestion):
Not sure whether we decided to ignore `closeFuture` errors entirely or not – it seems completely reasonable to ignore them though. 

Suspect @FranzBusch has opinions.

Code after:
    /// - Important: After this method returned the underlying ``Channel`` will be closed.
    ///
    /// - Parameter body: A closure that gets scoped access to the inbound and outbound.
    public func executeThenClose<Result>(
        _ body: (_ inbound: NIOAsyncChannelInboundStream<Inbound>, _ outbound: NIOAsyncChannelOutboundWriter<Outbound>)
            async throws -> Result
    ) async throws -> Result {
        let result: Result
        do {
            result = try await body(self._inbound, self._outbound)
        } catch let bodyError {
            do {
                self._outbound.finish()
                try await self.channel.close().get()
                throw bodyError
            } catch {
                throw bodyError
            }
        }

        self._outbound.finish()
        // We ignore errors from close, since all we care about is that the channel has been closed
        // at this point.
        self.channel.close(promise: nil)
        // `closeFuture` should never be failed, so we could ignore the error. However, do an
        // assertionFailure to guide bad Channel implementations that are incorrectly failing this
        // future to stop failing it.
        do {
            try await self.channel.closeFuture.get()
        } catch {
            assertionFailure(
                """
                The channel's closeFuture should never be failed, but it was failed with error: \(error).
                This is an error in the channel's implementation.
                Refer to `Channel/closeFuture`'s documentation for more information.
                """
            )
        }

        return result
    }
}

// swift-format-ignore: AmbiguousTrailingClosureOverload
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
extension NIOAsyncChannel {
    /// Provides scoped access to the inbound side of the underlying ``Channel``.
    ///
    /// - Important: After this method returned the underlying ``Channel`` will be closed.
    ///
    /// - Parameter body: A closure that gets scoped access to the inbound.