///|
/// The ASGI lifespan protocol (← uvicorn `LifespanOn`) driven in-process over
/// two async queues — no socket. The app parks under a `Lifespan` scope; the
/// driver pushes `lifespan.startup`, the app answers `startup.complete`, then
/// `lifespan.shutdown` and `shutdown.complete`, in that fixed order.
///
/// moon run src/examples/02-lifespan --target native
#coverage.skip
async fn main {
@async.with_task_group(g => {
let log : Array[String] = []
let app : @moonasgi.AsgiApp = (scope, receive, send) => {
guard scope is Lifespan(_) else { return }
for ;; {
match receive() {
LifespanStartup => {
log.push("startup")
send(@moonasgi.Event::LifespanStartupComplete)
}
LifespanShutdown => {
log.push("shutdown")
send(@moonasgi.Event::LifespanShutdownComplete)
break
}
_ => ()
}
}
}
let lifespan = @mooncat.Driver::new(app)
lifespan.spawn(g)
lifespan.startup()
println("after startup : \{join(log)}")
lifespan.shutdown()
println("after shutdown: \{join(log)}")
})
}
///|
/// Join log entries with an arrow so the ordered protocol reads left to right.
fn join(a : Array[String]) -> String {
let sb = StringBuilder()
for i = 0; i < a.length(); i = i + 1 {
if i > 0 {
sb.write_string(" -> ")
}
sb.write_string(a[i])
}
sb.to_string()
}