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

Code before:
    @usableFromInline typealias WhenCompleteBlocking = (Result<Value, Error>) -> Void
    #endif
    
    @inlinable
    func _whenCompleteBlocking(onto queue: DispatchQueue, _ callbackMayBlock: @escaping WhenCompleteBlocking) {
        self.whenComplete { value in
            queue.async { callbackMayBlock(value) }
        }
    }
}

// MARK: assertion

extension EventLoopFuture {
    /// Returns a new `EventLoopFuture` that asserts the original future's success.
    ///
    /// If the original future fails, it triggers an assertion failure, causing a runtime error during development.
    @inlinable
    public func assertSuccess() -> EventLoopFuture<Value> {
        let promise = self.eventLoop.makePromise(of: Value.self)
        self.whenComplete { result in
            switch result {
            case .success(let value):
                promise.succeed(value)
            case .failure(let error):
                assertionFailure("Expected success, but got failure: \(error)")
                promise.fail(error)
            }
        }
        return promise.futureResult
    }

    /// Returns a new `EventLoopFuture` that asserts the original future's failure.
    ///
    /// If the original future succeeds, it triggers an assertion failure, causing a runtime error during development.
    @inlinable
    public func assertFailure() -> EventLoopFuture<Value> {
        let promise = self.eventLoop.makePromise(of: Value.self)
        self.whenComplete { result in
            switch result {
            case .success(let value):
                assertionFailure("Expected failure, but got success: \(value)")
                promise.succeed(value)
            case .failure(let error):
                promise.fail(error)
            }
        }
        return promise.futureResult
    }

    /// Returns a new `EventLoopFuture` that preconditions the original future's success.

Review comment (bug):
Can we pass `file` and `line` through from the line that calls `assertSuccess`? That'll make the crash more generally useful.

Code after:
    @usableFromInline typealias WhenCompleteBlocking = (Result<Value, Error>) -> Void
    #endif
    
    @inlinable
    func _whenCompleteBlocking(onto queue: DispatchQueue, _ callbackMayBlock: @escaping WhenCompleteBlocking) {
        self.whenComplete { value in
            queue.async { callbackMayBlock(value) }
        }
    }
}

// MARK: assertion

extension EventLoopFuture {
    /// Attaches a callback to the `EventLoopFuture` that asserts the original future's success.
    ///
    /// If the original future fails, it triggers an assertion failure, causing a runtime error during development.
    /// The assertion failure will include the file and line of the calling site.
    ///
    /// - parameters:
    ///     - file: The file this function was called in, for debugging purposes.
    ///     - line: The line this function was called on, for debugging purposes.
    @inlinable
    public func assertSuccess(file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Value> {
        return self.always { result in
            switch result {
            case .success:
                ()
            case .failure(let error):
                assertionFailure("Expected success, but got failure: \(error)", file: file, line: line)
            }
        }
    }
    /// Attaches a callback to the `EventLoopFuture` that asserts the original future's failure.
    ///
    /// If the original future succeeds, it triggers an assertion failure, causing a runtime error during development.
    /// The assertion failure will include the file and line of the calling site.
    ///
    /// - parameters:
    ///     - file: The file this function was called in, for debugging purposes.
    ///     - line: The line this function was called on, for debugging purposes.
    @inlinable
    public func assertFailure(file: StaticString = #fileID, line: UInt = #line) -> EventLoopFuture<Value> {
        return self.always { result in
            switch result {
            case .success(let value):
                assertionFailure("Expected failure, but got success: \(value)", file: file, line: line)
            case .failure:
                ()
            }
        }