/*:#localized(key: "ProducingWithAsyncStream")
 # Producing a sequence with AsyncStream

 Consuming is half the story. Most of the time *you* are the one with values
 trickling in (from a timer, a location callback, a Bluetooth sensor), and you want
 to hand them to a `for await` loop. **`AsyncStream` is the tool that turns a source
 of one-at-a-time values into an async sequence.**

 You create it with a closure that receives a **continuation**, an object you call
 to push values into the stream:

 * `continuation.yield(value)` emits one element to whoever is looping.
 * `continuation.finish()` ends the stream, so the consumer's loop stops.

 Let's wire up the rooftop weather station. It emits a reading roughly every 0.3
 seconds, five times, then finishes.
 */
//#-editable-code
import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let readings = AsyncStream<Double> { continuation in
    // The closure kicks off the work that feeds the stream.
    Task {
        for step in 1...5 {
            // Wait between samples. try? because sleep throws on
            // cancellation (more on that below).
            try? await Task.sleep(for: .milliseconds(300))
            let celsius = Double.random(in: 18...26)
            print("📡 sensor emits reading \(step)")
            continuation.yield(celsius)
        }
        continuation.finish()   // no more readings: end the stream
    }
}

Task {
    for await celsius in readings {
        let rounded = (celsius * 10).rounded() / 10
        print("🌡️ received \(rounded)°C")
    }
    print("✅ Stream finished: sensor is done for the day")
    PlaygroundPage.current.finishExecution()
}
//#-end-editable-code
/*:#localized(key: "ProducingWithAsyncStream-2")
 **Watch it run:** the two `print` lines interleave, one pair at a time, about every
 0.3 seconds: `sensor emits reading 1`, then `received ...°C`, then a pause, then
 reading 2, and so on. After the fifth reading, `finish()` ends the stream, the loop
 exits, and `Stream finished` prints. You're literally watching values arrive over
 time, which no plain array could show you.

 * callout(Try it): Change `1...5` to `1...8` and the delay to `.milliseconds(150)`.
 The stream now emits more readings, faster. The `finish()` line still ends it
 cleanly.

 A few things worth naming:

 * The closure runs its own `Task` to do the waiting. `yield` can be called from
 anywhere, any number of times: from a timer, a delegate method, a completion
 handler. Each call delivers one element to the loop.
 * If nobody has awaited the next value yet, `AsyncStream` **buffers** it, so you
 won't lose a reading that arrives while the consumer is busy.
 * The values you yield should be **`Sendable`**: they hop from the producing task
 to the consuming one. `Double` and `Int` already are, so Swift 6's data-race
 checking stays quiet here.

 [Previous](@previous)  |  page 3 of 7  |  [Next: Cleaning Up with onTermination](@next)
 */
