/*:#localized(key: "CancellingGracefully")
 # Cancelling gracefully with `isCancelled`

 Throwing isn't the only option. Sometimes you want to stop and return *what
 you've done so far* rather than error out. That's what `Task.isCancelled` is
 for: check it, and return a partial result cleanly. Here the barista wipes
 tables until closing time, then reports how many they managed.
 */
//#-editable-code
import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let wiping = Task { () -> Int in
    var wiped = 0
    while !Task.isCancelled {
        wiped += 1
        print("Wiped table \(wiped)")
        try? await Task.sleep(for: .milliseconds(200))
    }
    print("Closing time: wiped \(wiped) tables total")
    return wiped
}

Task {
    try? await Task.sleep(for: .milliseconds(700))
    wiping.cancel()
    let total = await wiping.value   // no `try`: this task never throws
    print("Reported total: \(total)")
    PlaygroundPage.current.finishExecution()
}
//#-end-editable-code
/*:#localized(key: "CancellingGracefully-2")
 **Watch it run:** a handful of `Wiped table...` lines, then the loop sees
 `isCancelled` flip to `true`, exits normally, and returns the count. No
 error, no `try`: cancellation here is just a signal to finish up. Notice
 `await wiping.value` doesn't need `try` because this task can't throw.

 [Previous](@previous)  |  page 8 of 11  |  [Next: What Cancellation Is Not](@next)
 */
