/*:#localized(key: "FailingWithAResult")
 # When the callback can fail: a `Result`

 Most real callback APIs can also *fail*. For those you reach for
 **`withCheckedThrowingContinuation`**, the throwing sibling: its
 continuation can resume by *throwing* as well as returning, so a failed
 callback makes the awaiting call throw.

 Old callback APIs report failure in two classic shapes. You'll bridge both,
 starting with a `Result`.

 If the callback hands you a `Result<Success, Failure>`, there's a one-liner:
 `continuation.resume(with: result)`. It unwraps the `Result` for you:
 resuming with the value on `.success`, throwing on `.failure`.
 */
//#-editable-code
import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

enum StockError: Error {
    case unknownItem(String)
}

// Legacy API that reports success/failure with a Result.
func lookUpRoast(
    named name: String,
    completion: @escaping @Sendable (Result<String, Error>) -> Void
) {
    DispatchQueue.global().asyncAfter(deadline: .now() + 0.3) {
        if name == "Guji" {
            completion(.success("Ethiopia Guji: bright, floral"))
        } else {
            completion(.failure(StockError.unknownItem(name)))
        }
    }
}

func roastDescription(named name: String) async throws -> String {
    try await withCheckedThrowingContinuation { continuation in
        lookUpRoast(named: name) { result in
            continuation.resume(with: result)   // unwraps for you
        }
    }
}

Task {
    do {
        print(try await roastDescription(named: "Guji"))
        print(try await roastDescription(named: "Mystery"))
    } catch {
        print("Lookup failed: \(error)")
    }
    PlaygroundPage.current.finishExecution()
}
//#-end-editable-code
/*:#localized(key: "FailingWithAResult-2")
 **Watch it run:** the first lookup resolves after a short pause and prints
 the tasting note. The second resumes by **throwing**, so control jumps to
 the `catch` and prints `Lookup failed: unknownItem("Mystery")`. From the
 caller's side it reads like ordinary `try await`: the callback and the
 `Result` are gone.

 * callout(Try it): Change the second lookup from `"Mystery"` to `"Guji"`.
 Now both resolve by returning, both tasting notes print, and the `catch`
 never runs.

 [Previous](@previous)  |  page 3 of 8  |  [Next: Failing with a (Value, Error) Pair](@next)
 */
