/*---------------------------------------------------------------------------
  Copyright 2018-2026, Tim Whiting, Microsoft Research, Daan Leijen

  This is free software; you can redistribute it and/or modify it under the
  terms of the Apache License, Version 2.0. A copy of the License can be
  found in the LICENSE file at the root of this distribution.
---------------------------------------------------------------------------*/

/* Asynchronous primitives.

This module is based closely on [@Leijen:async] and aims to have robust and composable asynchronous
primitives. In particular, any outstanding asynchronous operation can be canceled (through `cancel-outstanding`)
within a certain cancelation scope which allows for composable primitives like `timeout` and `interleave`.

# Cancelation

When calling `cancel-outstanding`, it cancels any outstanding async operations
in the current cancelation scope and any of its child scopes.
Some reasons for cancelation:
 - returning normally, cancelation prevents dangling callbacks
 - returning abnormally (e.g. an exception), we cancel any pending callbacks
 - within a `firstof`, we have decided to cancel all remaining strands after
   the first is one completes

After `cancel-outstanding` is called, the caller continues as normal -
calling `cancel-oustanding` simply returns `()`.

The way that cancelation is observed is that all outstanding async operaions in
the cancelation scope receive a `Cancel` result instead of a `Result` (or `Exception`).
Aside from low-level code, a user won't observe this as the abstractions
awaiting a result automatically use `discontinue()` when `Cancel` a result
is given.

We use a separate effect `:discontinue` instead of an exception since it
is intended that a `discontinue` is never handled and always discontinues
a stsrand. Of course, `finally` blocks still execute so external resources
can be released properly.

# References

~ Bibliography { caption:"0" }
~~ BibItem { #Leijen:async; bibitem-label:"[1]"; searchterm:"Leijen+Daan+Structured+Asynchrony+with+Algebraic+Effects" }
Daan Leijen.
_Structured Asynchrony with Algebraic Effects_.
Microsoft Research technical report MSR-TR-2017-21, May 2017.
[pdf](https://www.microsoft.com/en-us/research/wp-content/uploads/2017/05/asynceffects-msr-tr-2017-21.pdf)
~~
~
\/
*/
module async/asyncstd/async/async

import std/num/int64std/num/int64
import std/core/undivstd/core/undiv
import std/core/unsafestd/core/unsafe
import std/num/float64std/num/float64
import std/time/durationstd/time/duration
import async/internalasync/internal

import async/api/evloopasync/api/uv/evloop
  [host=libc|jsnode]    async/api/uv/evloopasync/api/uv/evloop        // libuv for C or node for javascript
  [host=jsweb|wasmweb]  evloop       // javascript or wasm (emscripten) in a browser
  // todo: wasm standalone using wasi


pubstd/async/async/discontinue: (E, V) -> V effect discontinuestd/async/async/discontinue: (E, V) -> V
  // Internal: The current strand of execution is canceled
  final ctl discontinue() : aa: V

// The asynchronous effect is composed of four primitive effects.
// `:async-await` allows awaiting asynchronous operations,
// `:async-cancel` allows cancelation of outstanding asynchronous operations,
// `:async-ioc` allows execution of linear I/O (`:ioc`) at the handler scope,
// and `:discontinue` discontinues any running strand (using `final ctl`).
pub alias asyncstd/async/async/async: E = <std/core/types/total: Easync-awaitstd/async/internal/async-await: (E, V) -> V,async-iocstd/async/internal/async-ioc: (E, V) -> V,async-cancelstd/async/internal/async-cancel: (E, V) -> V,discontinuestd/async/async/discontinue: (E, V) -> V>

// Cancel any _other_ outstanding operations that are interleaved and
// part of the same cancelation scope (see `cancelation-scope`).
pub fun cancel-outstandingstd/async/async/cancel-outstanding: () -> async-cancel ()()result: -> async-cancel ()
  cancel-scopestd/async/internal/cancel-scope: (scope : async-scope) -> async-cancel ()(async-scopestd/async/internal/async-scope: -> async-cancel async-scope)

// Is the current cancelation canceled?
pub fun is-canceledstd/async/async/is-canceled: () -> async-cancel bool()result: -> async-cancel bool
  is-scope-canceledstd/async/internal/is-scope-canceled: (scope : async-scope) -> async-cancel bool(async-scopestd/async/internal/async-scope: -> async-cancel async-scope)

// Perform a stateful operation in the outer async handler.
pub fun async-ststd/async/async/async-st: forall<a> (action : () -> (st<global>) a) -> async a(actionaction: () -> (st<global>) $463: () -> ststd/core/types/st: H -> E<globalstd/core/types/global: H> aa: V)result: -> async 484: asyncstd/async/async/async: E aa: V
  async-iocstd/async/internal/async-ioc: (action : () -> ioc $463) -> async $463(actionaction: () -> ioc $463)

// Show an await result
pub fun await-result/showstd/async/async/await-result/show: forall<a> (r : await-result<a>, @implicit/show : (a) -> string) -> string(rr: await-result<$489>: await-resultstd/async/internal/await-result: V -> V<aa: V>, @implicit/show?show: ($489) -> string : aa: V -> stringstd/core/types/string: V)result: -> total string : stringstd/core/types/string: V
  match rr: await-result<$489>
    Cancelstd/async/internal/Cancel: forall<a> await-result<a>         -> "Cancel"literal: string
count= 6
Exceptionstd/async/internal/Exception: forall<a> (exn : exception) -> await-result<a>(exnexn: exception) -> "Exception("literal: string
count= 10
++std/core/types/(++): (x : string, y : string) -> string exn/showstd/core/exn/show: (exn : exception) -> string(exnexn: exception) ++std/core/types/(++): (x : string, y : string) -> string ")"literal: string
count= 1
Resultstd/async/internal/Result: forall<a> (value : a) -> await-result<a>(xx: $489) -> "Result("literal: string
count= 7
++std/core/types/(++): (x : string, y : string) -> string xx: $489.show?show: ($489) -> string ++std/core/types/(++): (x : string, y : string) -> string ")"literal: string
count= 1
// ---------------------------------------------------------------------------- // Asynchronous timeout and waiting // ---------------------------------------------------------------------------- // Wait (asynchronously) for `secs` seconds as a `:double`. // Use `yield()` to yield to other asynchronous operations. pub fun float/waitstd/async/async/float/wait: (secs : float64) -> async ()( secssecs: float64 : float64std/core/types/float64: V )result: -> async () : asyncstd/async/async/async: E (std/core/types/unit: V)std/core/types/unit: V waitstd/async/async/duration/wait: (secs : ? duration) -> async ()(secssecs: float64.durationstd/time/duration/float64/duration: (secs : float64) -> async duration) // Wait (asynchronously) for optional `secs` seconds `:duration` (`= 0.seconds` or `100.milli-seconds`). // Use `yield()` to yield generally to other asynchronous operations. pub fun duration/waitstd/async/async/duration/wait: (secs : ? duration) -> async ()( secssecs: ? duration : durationstd/time/duration/duration: V = zerostd/time/duration/zero: duration )result: -> async () : asyncstd/async/async/async: E (std/core/types/unit: V)std/core/types/unit: V val msecsmsecs: int64 = maxstd/num/int64/max: (i : int64, j : int64) -> async int64(zerostd/num/int64/zero: int64:int64std/core/types/int64: V,secssecs: duration.milli-secondsstd/time/duration/milli-seconds: (d : duration) -> async int.int64std/num/int64/int64: (i : int) -> async int64) await-errorstd/async/async/setup/await-error: (label : string, setup : (evloop : event-loop, resume : (()) -> ioc ()) -> ioc error<dispose-fn>) -> async error<()>("wait "literal: string
count= 5
++std/core/types/(++): (x : string, y : string) -> async string secssecs: duration.showstd/time/duration/show: (d : duration, max-prec : ? int) -> async string) fnfn: (evloop : event-loop, resume : (()) -> ioc ()) -> ioc error<() -> ioc ()>(evloopevloop: event-loop,resumeresume: (()) -> ioc ()) // ignore errors; we assume timeouts always work timer-setupstd/async/api/uv/evloop/timer-setup: (evloop : any, millisecs : int64, cb : () -> ioc ()) -> ioc error<() -> ioc ()>(evloopevloop: event-loop,msecsmsecs: int64,fnfn: () -> ioc ()() resumeresume: (()) -> ioc ()((std/core/types/Unit: ())std/core/types/Unit: ())) (std/core/types/Unit: ()
)std/core/types/Unit: () // Yield to other asynchronous operations. Same as `wait(0)`. pub fun yieldstd/async/async/yield: () -> async ()()result: -> async () : asyncstd/async/async/async: E (std/core/types/unit: V)std/core/types/unit: V duration/waitstd/async/async/duration/wait: (secs : ? duration) -> async ()() // ---------------------------------------------------------------------------- // Await wrappers // ---------------------------------------------------------------------------- // Convenience function for awaiting a zero argument callback that never fails fun await0-noexnstd/async/async/await0-noexn: (label : ? string, setup : (resume : () -> ioc ()) -> ioc ()) -> async ()( labellabel: ? string : stringstd/core/types/string: V = ""literal: string
count= 0
, setupsetup: (resume : () -> ioc ()) -> ioc () : (resume : () -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V ) -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V )result: -> async () : asyncstd/async/async/async: E (std/core/types/unit: V)std/core/types/unit: V await1-noexnstd/async/async/await1-noexn: (label : ? string, setup : (resume : (()) -> ioc ()) -> ioc ()) -> async ()(labellabel: string) fnfn: (resume : (()) -> ioc ()) -> ioc ()(resumeresume: (()) -> ioc ()) setupsetup: (resume : () -> ioc ()) -> ioc ()(fnfn: () -> ioc ()() resumeresume: (()) -> ioc ()((std/core/types/Unit: ())std/core/types/Unit: ())
) // Convenience function for awaiting a single argument callback that never fails pub fun await1-noexnstd/async/async/await1-noexn: forall<a> (label : ? string, setup : (resume : (a) -> ioc ()) -> ioc ()) -> async a( labellabel: ? string : stringstd/core/types/string: V = ""literal: string
count= 0
, setupsetup: (resume : ($1160) -> ioc ()) -> ioc () : (resume : (aa: V) -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V ) -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V )result: -> async 1197 : asyncstd/async/async/async: E aa: V await-noexnstd/async/async/await-noexn: (label : ? string, setup : (evloop : event-loop, resume : ($1160) -> ioc ()) -> ioc dispose-fn) -> async $1160(labellabel: string) fnfn: (event-loop, resume : ($1160) -> ioc ()) -> ioc (() -> ioc ())(_evloop,resumeresume: ($1160) -> ioc ()){ setupsetup: (resume : ($1160) -> ioc ()) -> ioc ()(resumeresume: ($1160) -> ioc ()); (fnfn: () -> ioc ()() {std/core/types/Unit: ()}std/core/types/Unit: ())
} // Convenience function for async functions where the setup cannot fail. In that case // the result will never be an error. fun await-noexnstd/async/async/await-noexn: forall<a> (label : ? string, setup : (evloop : event-loop, resume : (a) -> ioc ()) -> ioc dispose-fn) -> async a( labellabel: ? string : stringstd/core/types/string: V = ""literal: string
count= 0
, setupsetup: (evloop : event-loop, resume : ($995) -> ioc ()) -> ioc dispose-fn : (evloop : event-loopstd/async/internal/event-loop: V, resume : (aa: V) -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V) -> iocstd/core/ioc: E dispose-fnstd/async/internal/dispose-fn: V )result: -> async 1155 : asyncstd/async/async/async: E aa: V val resres: error<$995> = setup/await-errorstd/async/async/setup/await-error: (label : string, setup : (evloop : event-loop, resume : ($995) -> ioc ()) -> ioc error<dispose-fn>) -> async error<$995>( labellabel: string, fnfn: (evloop : event-loop, resume : ($995) -> ioc ()) -> ioc result<dispose-fn,exception>(evloopevloop: event-loop,resumeresume: ($995) -> ioc ()) setupsetup: (evloop : event-loop, resume : ($995) -> ioc ()) -> ioc dispose-fn(evloopevloop: event-loop,resumeresume: ($995) -> ioc ()).Okstd/core/types/Ok: forall<a,b> (value : a) -> result<a,b> ) match resres: error<$995> Okstd/core/types/Ok: forall<a,b> (value : a) -> result<a,b>(xx: $995) -> xx: $995 Errorstd/core/types/Error: forall<a,b> (error : b) -> result<a,b>(exnexn: exception) -> impossiblestd/core/debug/impossible: (message : ? string, @implicit/kk-file-line : string) -> async $995
?kk-file-line=debug/file/kk-file-line(debug/file/kk-file,debug/file/kk-line)
("unexpected exception returned from async await: "literal: string
count= 48
++std/core/types/(++): (x : string, y : string) -> async string showstd/core/exn/show: (exn : exception) -> async string(exnexn: exception)
) // Await a zero argument callback. pub fun await0std/async/async/await0: (label : ? string, setup : (resume : () -> ioc ()) -> ioc error<dispose-fn>) -> <async,exn> ()( labellabel: ? string : stringstd/core/types/string: V = ""literal: string
count= 0
, setupsetup: (resume : () -> ioc ()) -> ioc error<dispose-fn> : (resume : () -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V ) -> iocstd/core/ioc: E errorstd/core/exn/error: V -> V<dispose-fnstd/async/internal/dispose-fn: V> )result: -> <async,exn> () : <std/core/types/total: Easyncstd/async/async/async: E,exnstd/core/exn/exn: (E, V) -> V> (std/core/types/unit: V)std/core/types/unit: V await1std/async/async/await1: (label : ? string, setup : (resume : (()) -> ioc ()) -> ioc error<dispose-fn>) -> <async,exn> ()(labellabel: string) fnfn: (resume : (()) -> ioc ()) -> ioc error<dispose-fn>(resumeresume: (()) -> ioc ()) setupsetup: (resume : () -> ioc ()) -> ioc error<dispose-fn>(fnfn: () -> ioc ()() resumeresume: (()) -> ioc ()((std/core/types/Unit: ())std/core/types/Unit: ())
) // Await a single argument callback. pub fun await1std/async/async/await1: forall<a> (label : ? string, setup : (resume : (a) -> ioc ()) -> ioc error<dispose-fn>) -> <async,exn> a( labellabel: ? string : stringstd/core/types/string: V = ""literal: string
count= 0
, setupsetup: (resume : ($1376) -> ioc ()) -> ioc error<dispose-fn> : (resume : (aa: V) -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V ) -> iocstd/core/ioc: E errorstd/core/exn/error: V -> V<dispose-fnstd/async/internal/dispose-fn: V> )result: -> <async,exn> 1425 : <std/core/types/total: Easyncstd/async/async/async: E,exnstd/core/exn/exn: (E, V) -> V> aa: V setup/awaitstd/async/async/setup/await: (label : ? string, setup : (evloop : event-loop, resume : (error<$1376>) -> ioc ()) -> ioc error<dispose-fn>) -> <async,exn> $1376(labellabel: string) fnfn: (event-loop, resume : (error<$1376>) -> ioc ()) -> ioc error<dispose-fn>(_evloop,resumeresume: (error<$1376>) -> ioc ()) setupsetup: (resume : ($1376) -> ioc ()) -> ioc error<dispose-fn>(fnfn: (x : $1376) -> ioc ()(xx: $1376) resumeresume: (error<$1376>) -> ioc ()(Okstd/core/types/Ok: forall<a,b> (value : a) -> result<a,b>(xx: $1376))
) // Await with the exception effect pub fun setup/awaitstd/async/async/setup/await: forall<a> (label : ? string, setup : (evloop : event-loop, resume : (error<a>) -> ioc ()) -> ioc error<dispose-fn>) -> <async,exn> a( labellabel: ? string : stringstd/core/types/string: V = ""literal: string
count= 0
, setupsetup: (evloop : event-loop, resume : (error<$1340>) -> ioc ()) -> ioc error<dispose-fn> : (evloop : event-loopstd/async/internal/event-loop: V, resume : errorstd/core/exn/error: V -> V<aa: V> -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V) -> iocstd/core/ioc: E errorstd/core/exn/error: V -> V<dispose-fnstd/async/internal/dispose-fn: V> )result: -> <async,exn> 1371 : <std/core/types/total: Easyncstd/async/async/async: E,exnstd/core/exn/exn: (E, V) -> V> aa: V await-error1std/async/async/setup/await-error1: (label : string, setup : (evloop : event-loop, resume : (error<$1340>) -> ioc ()) -> ioc error<dispose-fn>) -> <async,exn> error<$1340>(labellabel: string,setupsetup: (evloop : event-loop, resume : (error<$1340>) -> ioc ()) -> ioc error<dispose-fn>).untrystd/core/exn/untry: (err : error<$1340>) -> <async,exn> $1340
// Primitive await: call `setup` to set up an asynchronous callback with the host platform. // The setup is passed the eventloop of the async handler, and a `resume` function // that takes an `:await-result`: a cancelation, exception, or regular result. // The `setup` function returns either an error, or a `dispose` funcion that is invoked on cancellation // to dispose of any resources (see the implementation of `wait`). // The `resume` is invoked exactly once (either on the async completion callback, or on cancelation) pub fun setup/await-errorstd/async/async/setup/await-error: forall<a> (label : string, setup : (evloop : event-loop, resume : (a) -> ioc ()) -> ioc error<dispose-fn>) -> async error<a>( labellabel: string : stringstd/core/types/string: V, setupsetup: (evloop : event-loop, resume : ($784) -> ioc ()) -> ioc error<dispose-fn> : (evloop : event-loopstd/async/internal/event-loop: V, resume : (aa: V) -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V) -> iocstd/core/ioc: E errorstd/core/exn/error: V -> V<dispose-fnstd/async/internal/dispose-fn: V> )result: -> async error<840> : asyncstd/async/async/async: E errorstd/core/exn/error: V -> V<aa: V> val resres: await-result<$784> = do-awaitstd/async/internal/do-await: (setup : await-setup<$784>, async-scope : async-scope, label : string) -> async await-result<$784>(fnfn: (evloop : event-loop, resume : (result : await-result<$784>, isdone : bool) -> ioc ()) -> ioc error<dispose-fn>(evloopevloop: event-loop,resumeresume: (result : await-result<$784>, isdone : bool) -> ioc ()) { setupsetup: (evloop : event-loop, resume : ($784) -> ioc ()) -> ioc error<dispose-fn>(evloopevloop: event-loop, fnfn: (res : $784) -> ioc ()(resres: $784) resumeresume: (result : await-result<$784>, isdone : bool) -> ioc ()(Resultstd/async/internal/Result: forall<a> (value : a) -> await-result<a>(resres: $784),Truestd/core/types/True: bool)) }, async-scopestd/async/internal/async-scope: -> async-cancel async-scope, labellabel: string) resres: await-result<$784>.errorstd/async/async/await-result/error: (res : await-result<$784>, @implicit/label : string) -> async error<$784>
?label=label
pub fun setup/await-error1std/async/async/setup/await-error1: forall<a> (label : string, setup : (evloop : event-loop, resume : (error<a>) -> ioc ()) -> ioc error<dispose-fn>) -> async error<a>( labellabel: string : stringstd/core/types/string: V, setupsetup: (evloop : event-loop, resume : (error<$1279>) -> ioc ()) -> ioc error<dispose-fn> : (evloop : event-loopstd/async/internal/event-loop: V, resume : errorstd/core/exn/error: V -> V<aa: V> -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V) -> iocstd/core/ioc: E errorstd/core/exn/error: V -> V<dispose-fnstd/async/internal/dispose-fn: V> )result: -> async error<1335> : asyncstd/async/async/async: E errorstd/core/exn/error: V -> V<aa: V> val resres: await-result<$1279> = do-awaitstd/async/internal/do-await: (setup : await-setup<$1279>, async-scope : async-scope, label : string) -> async await-result<$1279>(fnfn: (evloop : event-loop, resume : (result : await-result<$1279>, isdone : bool) -> ioc ()) -> ioc error<dispose-fn>(evloopevloop: event-loop,resumeresume: (result : await-result<$1279>, isdone : bool) -> ioc ()) { setupsetup: (evloop : event-loop, resume : (error<$1279>) -> ioc ()) -> ioc error<dispose-fn>(evloopevloop: event-loop, fnfn: (eres : error<$1279>) -> ioc ()(ereseres: error<$1279>) resumeresume: (result : await-result<$1279>, isdone : bool) -> ioc ()(ereseres: error<$1279>.await-resultstd/async/async/error/await-result: (res : error<$1279>) -> ioc await-result<$1279>,Truestd/core/types/True: bool)) }, async-scopestd/async/internal/async-scope: -> async-cancel async-scope, labellabel: string) resres: await-result<$1279>.errorstd/async/async/await-result/error: (res : await-result<$1279>, @implicit/label : string) -> async error<$1279>
?label=label
fun error/await-resultstd/async/async/error/await-result: forall<a> (res : error<a>) -> await-result<a>( resres: error<$1237> : errorstd/core/exn/error: V -> V<aa: V> )result: -> total await-result<1274> : await-resultstd/async/internal/await-result: V -> V<aa: V> match resres: error<$1237> Errorstd/core/types/Error: forall<a,b> (error : b) -> result<a,b>(exnexn: exception) -> Exceptionstd/async/internal/Exception: forall<a> (exn : exception) -> await-result<a>(exnexn: exception) Okstd/core/types/Ok: forall<a,b> (value : a) -> result<a,b>(valuevalue: $1237) -> Resultstd/async/internal/Result: forall<a> (value : a) -> await-result<a>(valuevalue: $1237) fun await-result/errorstd/async/async/await-result/error: forall<a> (res : await-result<a>, @implicit/label : string) -> discontinue error<a>( resres: await-result<$729> : await-resultstd/async/internal/await-result: V -> V<aa: V>, @implicit/label?label: string : stringstd/core/types/string: V )result: -> discontinue error<779> : discontinuestd/async/async/discontinue: (E, V) -> V errorstd/core/exn/error: V -> V<aa: V> match resres: await-result<$729> Resultstd/async/internal/Result: forall<a> (value : a) -> await-result<a>(valuevalue: $729) -> Okstd/core/types/Ok: forall<a,b> (value : a) -> result<a,b>(valuevalue: $729) Exceptionstd/async/internal/Exception: forall<a> (exn : exception) -> await-result<a>(exnexn: exception) -> Errorstd/core/types/Error: forall<a,b> (error : b) -> result<a,b>(exnexn: exception) Cancelstd/async/internal/Cancel: forall<a> await-result<a> -> // trace("discontinue from await: " ++ label) discontinuestd/async/async/discontinue: () -> discontinue error<$729>() extend type exception-info ExnSyncstd/async/async/ExnSync: exception-info pub fun do-syncstd/async/async/do-sync: (action : (evloop : event-loop) -> ioc error<()>, label : ? string) -> <async,exn> ()( actionaction: (evloop : event-loop) -> ioc error<()> : (evloop : event-loopstd/async/internal/event-loop: V) -> iocstd/core/ioc: E errorstd/core/exn/error: V -> V<(std/core/types/unit: V)std/core/types/unit: V>, labellabel: ? string : stringstd/core/types/string: V = ""literal: string
count= 0
)result: -> <async,exn> () : <std/core/types/total: Eexnstd/core/exn/exn: (E, V) -> V,asyncstd/async/async/async: E> (std/core/types/unit: V)std/core/types/unit: V val resres: await-result<()> = do-awaitstd/async/internal/do-await: (setup : await-setup<()>, async-scope : async-scope, label : string) -> <async,exn> await-result<()>(fnfn: (evloop : event-loop, resume : (result : await-result<()>, isdone : bool) -> ioc ()) -> ioc result<dispose-fn,exception>(evloopevloop: event-loop,resumeresume: (result : await-result<()>, isdone : bool) -> ioc ()) { match actionaction: (evloop : event-loop) -> ioc error<()>(evloopevloop: event-loop) Errorstd/core/types/Error: forall<a,b> (error : b) -> result<a,b>(errerr: exception) -> Errorstd/core/types/Error: forall<a,b> (error : b) -> result<a,b>(errerr: exception) Okstd/core/types/Ok: forall<a,b> (value : a) -> result<a,b>(_) -> Errorstd/core/types/Error: forall<a,b> (error : b) -> result<a,b>(Exceptionstd/core/exn/Exception: (message : string, info : exception-info) -> exception("do-sync"literal: string
count= 7
,ExnSyncstd/async/async/ExnSync: exception-info)) }, async-scopestd/async/internal/async-scope: -> async-cancel async-scope, labellabel: string) match resres: await-result<()> Exceptionstd/async/internal/Exception: forall<a> (exn : exception) -> await-result<a>(Exceptionstd/core/exn/Exception: (message : string, info : exception-info) -> exception(_,ExnSyncstd/async/async/ExnSync: exception-info)) -> (std/core/types/Unit: ())std/core/types/Unit: () _ -> resres: await-result<()>.errorstd/async/async/await-result/error: (res : await-result<()>, @implicit/label : string) -> <async,exn> error<()>
?label=label
.untrystd/core/exn/untry: (err : error<()>) -> <async,exn> ()
// ---------------------------------------------------------------------------- // Default async handler // ---------------------------------------------------------------------------- fun noopstd/async/async/noop: () -> ()()result: -> total (): (std/core/types/unit: V)std/core/types/unit: V (std/core/types/Unit: ())std/core/types/Unit: () // The main async handler keeps a list of outstanding "callbacks" as `:await-resumption`s // This is used for cancelation and debugging. The scope of any await resumption // is always a unique (child) scope so can be used to uniquely identify an specific resumption. type await-resumptionstd/async/async/await-resumption: V AwaitResumptionstd/async/async/AwaitResumption: forall<a> (scope : async-scope, label : string, resume : (await-result<a>, bool) -> ioc ()) -> await-resumption<aa: V>( scopestd/async/async/await-resumption/scope: (await-resumption) -> async-scope : async-scopestd/async/internal/async-scope: V, labelstd/async/async/await-resumption/label: (await-resumption) -> string : stringstd/core/types/string: V, resume : (await-resultstd/async/internal/await-result: V -> V<aa: V>,boolstd/core/types/bool: V) -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V ) fun await-resumption/showstd/async/async/await-resumption/show: (await-resumption) -> string( AwaitResumptionstd/async/async/AwaitResumption: forall<a> (scope : async-scope, label : string, resume : (await-result<a>, bool) -> ioc ()) -> await-resumption(scopescope: async-scope,labellabel: string,_) )result: -> total string : stringstd/core/types/string: V labellabel: string ++std/core/types/(++): (x : string, y : string) -> string " at "literal: string
count= 4
++std/core/types/(++): (x : string, y : string) -> string scopescope: async-scope.showstd/async/internal/async-scope/show: (async-scope) -> string
// Remove a specific `:await-resumption` from the list. fun removestd/async/async/remove: (xs : list<await-resumption>, scope : async-scope) -> list<await-resumption>( xsxs: list<await-resumption> : liststd/core/types/list: V -> V<await-resumptionstd/async/async/await-resumption: V>, scopescope: async-scope : async-scopestd/async/internal/async-scope: V )result: -> total list<await-resumption> : liststd/core/types/list: V -> V<await-resumptionstd/async/async/await-resumption: V> match xsxs: list<await-resumption> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(AwaitResumptionstd/async/async/AwaitResumption: forall<a> (scope : async-scope, label : string, resume : (await-result<a>, bool) -> ioc ()) -> await-resumption(ss: async-scope,_),xxxx: list<await-resumption>) | ss: async-scope ==std/async/internal/async-scope/(==): (s1 : async-scope, s2 : async-scope) -> bool scopescope: async-scope -> xxxx: list<await-resumption> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: await-resumption,xxxx: list<await-resumption>) -> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(xx: await-resumption,removestd/async/async/remove: (xs : list<await-resumption>, scope : async-scope) -> list<await-resumption>(xxxx: list<await-resumption>,scopescope: async-scope)) Nilstd/core/types/Nil: forall<a> list<a> -> Nilstd/core/types/Nil: forall<a> list<a> // The outer `:async` effect handler. This is automatically applied by the compiler // around the `main` function if it has an `:async` effect. fun async-evloopstd/async/async/async-evloop: (evloop : event-loop, action : () -> <ioc,async> ()) -> ioc ()(evloopevloop: event-loop : event-loopstd/async/internal/event-loop: V, actionaction: () -> <ioc,async> () : () -> <std/core/types/total: Easyncstd/async/async/async: E,iocstd/core/ioc: E> (std/core/types/unit: V)std/core/types/unit: V )result: -> ioc () : iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V // Outstanding async requests val outstandingoutstanding: ref<global,list<await-resumption>> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,liststd/core/types/list: V -> V<await-resumptionstd/async/async/await-resumption: V>> = refstd/core/types/ref: (value : list<await-resumption>) -> ioc ref<global,list<await-resumption>>([std/core/types/Nil: forall<a> list<a>]std/core/types/Nil: forall<a> list<a>) // Has the root async-scope been canceled? val canceledcanceled: ref<global,bool> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,boolstd/core/types/bool: V> = refstd/core/types/ref: (value : bool) -> ioc ref<global,bool>(Falsestd/core/types/False: bool) // Setup a new async await request with a given callback `resume` fun setup-awaitsetup-await: forall<a> (setup : await-setup<a>, scope : async-scope, label : string, resume : (await-result<a>) -> ioc ()) -> ioc ()( setupsetup: await-setup<$1821> : await-setupstd/async/internal/await-setup: V -> V<aa: V>, scopescope: async-scope : async-scopestd/async/internal/async-scope: V, labellabel: string : stringstd/core/types/string: V, resumeresume: (await-result<$1821>) -> ioc () : (await-resultstd/async/internal/await-result: V -> V<aa: V>) -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V)result: -> ioc () : iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V // Each callback gets its own async-scope so we can tell when a given // callback can be removed from `outstanding` val cscopecscope: async-scope = new-child-scope-iocstd/async/internal/new-child-scope-ioc: (async-scope) -> ioc async-scope(scopescope: async-scope) // `disposer` holds the dispose function (that releases resources on cancelation) val disposerdisposer: ref<global,dispose-fn> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,dispose-fnstd/async/internal/dispose-fn: V> = refstd/core/types/ref: (value : dispose-fn) -> ioc ref<global,dispose-fn>(noopstd/async/async/noop: () -> ioc ()) // The resumption callback that is invoked when the async request completes (or on cancelation) fun resume-cbresume-cb: (res : await-result<$1821>, is-done : bool) -> ioc ()( resres: await-result<$1821> : await-resultstd/async/internal/await-result: V -> V<__w-l239-c39: V>, is-doneis-done: bool : boolstd/core/types/bool: V )result: -> ioc (): iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V if is-doneis-done: bool then outstandingoutstanding: ref<global,list<await-resumption>> :=std/core/types/set: (ref : ref<global,list<await-resumption>>, assigned : list<await-resumption>) -> ioc () (!std/core/types/ref/(!): (ref : ref<global,list<await-resumption>>, @implicit/hdiv : hdiv<global,list<await-resumption>,<write<global>,alloc<global>,console,div,fsys,ndet,net,ui>>) -> ioc list<await-resumption>
?hdiv=iev@1866
outstandingoutstanding: ref<global,list<await-resumption>>).removestd/async/async/remove: (xs : list<await-resumption>, scope : async-scope) -> ioc list<await-resumption>(cscopecscope: async-scope) val disposedispose: () -> ioc () = disposerdisposer: ref<global,dispose-fn>.swapstd/core/types/swap: (ref : ref<global,dispose-fn>, assigned : dispose-fn) -> ioc dispose-fn(noopstd/async/async/noop: () -> ioc ()) // unreference early if resres: await-result<$1821>.is-cancelstd/async/internal/is-cancel: (await-result : await-result<$1821>) -> ioc bool then disposedispose: () -> ioc ()()std/core/types/Unit: () resumeresume: (await-result<$1821>) -> ioc ()(resres: await-result<$1821>
) outstandingoutstanding: ref<global,list<await-resumption>> :=std/core/types/set: (ref : ref<global,list<await-resumption>>, assigned : list<await-resumption>) -> ioc () Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(AwaitResumptionstd/async/async/AwaitResumption: forall<a> (scope : async-scope, label : string, resume : (await-result<a>, bool) -> ioc ()) -> await-resumption(cscopecscope: async-scope,labellabel: string,resume-cbresume-cb: (res : await-result<$1821>, is-done : bool) -> ioc ()), !std/core/types/ref/(!): (ref : ref<global,list<await-resumption>>, @implicit/hdiv : hdiv<global,list<await-resumption>,<write<global>,alloc<global>,console,div,fsys,ndet,net,ui>>) -> ioc list<await-resumption>
?hdiv=iev@1965
outstandingoutstanding: ref<global,list<await-resumption>>) match(setupsetup: (evloop : event-loop, resume : (result : await-result<$1821>, isdone : bool) -> ioc ()) -> ioc error<dispose-fn>(evloopevloop: event-loop,resume-cbresume-cb: (res : await-result<$1821>, is-done : bool) -> ioc ())) // primitive setup: registers `resume-cb` as the callback for an async request Okstd/core/types/Ok: forall<a,b> (value : a) -> result<a,b>(disposedispose: dispose-fn) -> disposerdisposer: ref<global,dispose-fn> :=std/core/types/set: (ref : ref<global,dispose-fn>, assigned : dispose-fn) -> ioc () disposedispose: () -> ioc () Errorstd/core/types/Error: forall<a,b> (error : b) -> result<a,b>(exnexn: exception) -> resume-cbresume-cb: (res : await-result<$1821>, is-done : bool) -> ioc ()(Exceptionstd/async/internal/Exception: forall<a> (exn : exception) -> await-result<a>(exnexn: exception),Truestd/core/types/True: bool
) // if setup fails, we resume immediately with an exception result // Cancel all outstanding async requests that are in `scope` fun cancel-outstanding-in-scopecancel-outstanding-in-scope: (scope : async-scope) -> ioc ()( scopescope: async-scope : async-scopestd/async/internal/async-scope: V )result: -> ioc () : iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V (!std/core/types/ref/(!): (ref : ref<global,list<await-resumption>>, @implicit/hdiv : hdiv<global,list<await-resumption>,<alloc<global>,console,div,fsys,ndet,net,ui,write<global>>>) -> ioc list<await-resumption>
?hdiv=iev@2059
outstandingoutstanding: ref<global,list<await-resumption>>).foreachstd/core/list/foreach: (xs : list<await-resumption>, action : (await-resumption) -> ioc ()) -> ioc () fnfn: (await-resumption) -> ioc ()(AwaitResumptionstd/async/async/AwaitResumption: forall<a> (scope : async-scope, label : string, resume : (await-result<a>, bool) -> ioc ()) -> await-resumption(await-scopeawait-scope: async-scope,_label,resume-cbresume-cb: (await-result<$2091>, bool) -> ioc ())) if await-scopeawait-scope: async-scope <=std/async/internal/(<=): (async-scope, root : async-scope) -> ioc bool scopescope: async-scope then // trace("cancel: " ++ label ++ " at " ++ scope.show) resume-cbresume-cb: (await-result<$2091>, bool) -> ioc ()(Cancelstd/async/internal/Cancel: forall<a> await-result<a>,Truestd/core/types/True: bool
)std/core/types/Unit: () // else // trace("no cancel: " ++ label ++ " at " ++ scope.show) // Schedule an async call for the next evloop iteration (uv_check_t / setImmediate) fun scheduleschedule: (f : () -> ioc ()) -> ioc ()( ff: () -> ioc () : () -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V )result: -> ioc () : iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V match immediate-setupstd/async/api/uv/evloop/immediate-setup: (evloop : any, cb : () -> ioc ()) -> ioc error<() -> ioc ()>(evloopevloop: event-loop,ff: () -> ioc ()) Okstd/core/types/Ok: forall<a,b> (value : a) -> result<a,b> -> (std/core/types/Unit: ())std/core/types/Unit: () // scheduled f to be called Errorstd/core/types/Error: forall<a,b> (error : b) -> result<a,b> -> ff: () -> ioc ()() // if setup fails we call it immediately withwith: () -> <ioc,async-await> () handlerhandler: (() -> <ioc,async-await> ()) -> ioc ()<async-awaitstd/async/internal/async-await: (E, V) -> V> raw ctl do-awaitdo-await: (setup : await-setup<_2189>, scope : async-scope, lab : string, rcontext : resume-context<await-result<_2189>,ioc,<async-await|ioc>,()>) -> ioc ()
(setupsetup: await-setup<_2189>,scopescope: async-scope,lablab: string) setup-awaitsetup-await: (setup : await-setup<_2189>, scope : async-scope, label : string, resume : (await-result<_2189>) -> ioc ()) -> ioc ()(setupsetup: (evloop : event-loop, resume : (result : await-result<_2189>, isdone : bool) -> ioc ()) -> ioc error<dispose-fn>, scopescope: async-scope, lablab: string, fnfn: (x : await-result<_2189>) -> ioc ()(xx: await-result<_2189>) rcontextrcontext: resume-context<await-result<_2189>,ioc,<async-await|ioc>,()>.resumestd/core/hnd/resume: (r : resume-context<await-result<_2189>,ioc,<async-await|ioc>,()>, x : await-result<_2189>) -> ioc ()(xx: await-result<_2189>) ) fun no-awaitno-await: (setup : await-setup<_2192>, scope : async-scope, lab : string, cb : (await-result<_2192>) -> ioc ()) -> ioc ()(setupsetup: await-setup<_2192>,scopescope: async-scope,lablab: string,cbcb: (await-result<_2192>) -> ioc ()) setup-awaitsetup-await: (setup : await-setup<_2192>, scope : async-scope, label : string, resume : (await-result<_2192>) -> ioc ()) -> ioc ()(setupsetup: (evloop : event-loop, resume : (result : await-result<_2192>, isdone : bool) -> ioc ()) -> ioc error<dispose-fn>, scopescope: async-scope, lablab: string, cbcb: (await-result<_2192>) -> ioc () ) withwith: () -> <ioc,async-await,async-ioc> () handlerhandler: (() -> <ioc,async-await,async-ioc> ()) -> <ioc,async-await> ()<async-iocstd/async/internal/async-ioc: (E, V) -> V> fun async-iocasync-ioc: (f : () -> ioc _2354) -> <ioc,async-await> _2354(ff: () -> ioc _2354) ff: () -> <ioc,async-await> _2354() fun async-schedule-iocasync-schedule-ioc: (f : () -> ioc ()) -> <ioc,async-await> ()(ff: () -> ioc ()) scheduleschedule: (f : () -> ioc ()) -> <ioc,async-await> ()(ff: () -> ioc ()) withwith: () -> <ioc,async-await,async-cancel,async-ioc> () handlerhandler: (() -> <ioc,async-await,async-cancel,async-ioc> ()) -> <ioc,async-await,async-ioc> ()<async-cancelstd/async/internal/async-cancel: (E, V) -> V> val async-scopeasync-scope: () -> <ioc,async-await,async-ioc> async-scope = root-scopestd/async/internal/root-scope: async-scope fun is-scope-canceledis-scope-canceled: (scope : async-scope) -> <ioc,async-await,async-ioc> bool(scopescope: async-scope) (scopescope: async-scope==std/async/internal/async-scope/(==): (s1 : async-scope, s2 : async-scope) -> <ioc,async-await,async-ioc> boolroot-scopestd/async/internal/root-scope: async-scope &&std/core/types/(&&): (x : bool, y : bool) -> <ioc,async-await,async-ioc> bool !std/core/types/ref/(!): (ref : ref<global,bool>, @implicit/hdiv : hdiv<global,bool,<alloc<global>,console,div,fsys,ndet,net,ui,write<global>,async-await,async-ioc>>) -> <ioc,async-await,async-ioc> bool
?hdiv=iev@2780
canceledcanceled: ref<global,bool>) fun cancel-scopecancel-scope: (scope : async-scope) -> <ioc,async-await,async-ioc> ()(scopescope: async-scope) // trace("cancel-scope: " ++ scope.show) if scopescope: async-scope ==std/async/internal/async-scope/(==): (s1 : async-scope, s2 : async-scope) -> <ioc,async-await,async-ioc> bool root-scopestd/async/internal/root-scope: async-scope then canceledcanceled: ref<global,bool> :=std/core/types/set: (ref : ref<global,bool>, assigned : bool) -> <ioc,async-await,async-ioc> () Truestd/core/types/True: bool cancel-outstanding-in-scopecancel-outstanding-in-scope: (scope : async-scope) -> <ioc,async-await,async-ioc> ()(scopescope: async-scope) withwith: () -> <ioc,async> () handlerhandler: (() -> <ioc,async> ()) -> <ioc,async-await,async-cancel,async-ioc> ()<discontinuestd/async/async/discontinue: (E, V) -> V> final ctl discontinuediscontinue: () -> <ioc,async-await,async-cancel,async-ioc> ()() cancel-outstanding-in-scopecancel-outstanding-in-scope: (scope : async-scope) -> <ioc,async-await,async-cancel,async-ioc> ()(root-scopestd/async/internal/root-scope: async-scope) // trace("discontinue occurred at the toplevel async-scope") actionaction: () -> <ioc,async> ()(
) // The main `:async` handler. Uses "libuv" for the C backend, // (with a libuv emscripten wrapper for the Wasm Web backend). // Uses the standard async calls for Javascript (web or Node). pub fun asyncstd/async/async/async: (action : () -> <ioc,async> ()) -> ioc ()( actionaction: () -> <ioc,async> () : () -> <std/core/types/total: Easyncstd/async/async/async: E,iocstd/core/ioc: E> (std/core/types/unit: V)std/core/types/unit: V )result: -> ioc () : iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V val evloopevloop: any = event-loop-initstd/async/api/uv/evloop/event-loop-init: () -> ioc any() async-evloopstd/async/async/async-evloop: (evloop : event-loop, action : () -> <ioc,async> ()) -> ioc ()(evloopevloop: any,actionaction: () -> <ioc,async> ()) event-loop-runstd/async/api/uv/evloop/event-loop-run: (evloop : any) -> ioc ()(evloopevloop: any) // The default async handler called from `main`. pub fun @default-async( actionaction: () -> <ioc,async> () : () -> <std/core/types/total: Easyncstd/async/async/async: E,iocstd/core/ioc: E> (std/core/types/unit: V)std/core/types/unit: V )result: -> ioc () : iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V asyncstd/async/async/async: (action : () -> <ioc,async> ()) -> ioc ()(actionaction: () -> <ioc,async> ()) // ---------------------------------------------------------------------------- // Cancelation async-scope // ---------------------------------------------------------------------------- // Set up a new cancelation scope pub fun cancelation-scopestd/async/async/cancelation-scope: forall<a,e> (action : () -> <async|e> a) -> <async|e> a( actionaction: () -> <async|$2919> $2918 : () -> <asyncstd/async/async/async: E|ee: E> aa: V)result: -> <async|3300> 3299 : <asyncstd/async/async/async: E|ee: E> aa: V val cscopecscope: async-scope = new-child-scopestd/async/internal/new-child-scope: (scope : async-scope) -> <async,local<$2929>|$2919> async-scope(async-scopestd/async/internal/async-scope: -> async-cancel async-scope) var canceledcanceled: local-var<$2929,bool> := Falsestd/core/types/False: bool overridehandler: (() -> <async,async-cancel,local<$2929>|$2919> $2918) -> <async,local<$2929>|$2919> $2918 handle<async-cancelstd/async/internal/async-cancel: (E, V) -> V>(actionaction: () -> <async|$2919> $2918) val async-scopeasync-scope: () -> <async,local<$2929>|$2919> async-scope = cscopecscope: async-scope fun is-scope-canceledis-scope-canceled: (scope : async-scope) -> <async,local<$2929>|$2919> bool(scopescope: async-scope) (scopescope: async-scope<=std/async/internal/(<=): (async-scope, root : async-scope) -> <async,local<$2929>|$2919> boolcscopecscope: async-scope &&std/core/types/(&&): (x : bool, y : bool) -> <async,local<$2929>|$2919> bool canceledcanceled: bool
?hdiv=iev@3225
) ||std/core/types/(||): (x : bool, y : bool) -> <async,local<$2929>|$2919> bool is-scope-canceledstd/async/internal/is-scope-canceled: (scope : async-scope) -> <async,local<$2929>|$2919> bool(scopescope: async-scope) fun cancel-scopecancel-scope: (scope : async-scope) -> <async,local<$2929>|$2919> ()(scopescope: async-scope) if scopescope: async-scope==std/async/internal/async-scope/(==): (s1 : async-scope, s2 : async-scope) -> <async,local<$2929>|$2919> boolcscopecscope: async-scope then canceledcanceled: local-var<$2929,bool> :=std/core/types/local-set: (v : local-var<$2929,bool>, assigned : bool) -> <async,local<$2929>|$2919> () Truestd/core/types/True: bool cancel-scopestd/async/internal/cancel-scope: (scope : async-scope) -> <async,local<$2929>|$2919> ()(scopescope: async-scope
) // Run an `action` as if it is part of the parent scope // (so it will be canceled only if the parent scope is canceled) pub fun in-parent-scopestd/async/async/in-parent-scope: forall<a,e> (action : () -> <async|e> a) -> <async|e> a( actionaction: () -> <async|$3308> $3307 : () -> <asyncstd/async/async/async: E|ee: E> aa: V )result: -> <async|3455> 3454 : <asyncstd/async/async/async: E|ee: E> aa: V overridehandler: (() -> <async,async-cancel|$3308> $3307) -> <async|$3308> $3307 handle<async-cancelstd/async/internal/async-cancel: (E, V) -> V>(actionaction: () -> <async|$3308> $3307) val async-scopeasync-scope: () -> <async|$3308> async-scope = async-scopestd/async/internal/async-scope: -> async-cancel async-scope.parentstd/async/internal/parent: (async-scope) -> <async|$3308> async-scope fun is-scope-canceledis-scope-canceled: (scope : async-scope) -> <async|$3308> bool(scopescope: async-scope) is-scope-canceledstd/async/internal/is-scope-canceled: (scope : async-scope) -> <async|$3308> bool(scopescope: async-scope) fun cancel-scopecancel-scope: (scope : async-scope) -> <async|$3308> ()(scopescope: async-scope) cancel-scopestd/async/internal/cancel-scope: (scope : async-scope) -> <async|$3308> ()(scopescope: async-scope) // Catch a discontinue as a `:maybe`. // Use with care as cancelation should not be ignored. pub fun unsafe-uncancelstd/async/async/unsafe-uncancel: forall<a,e> (action : () -> <async|e> a) -> <async|e> maybe<a>( actionaction: () -> <async|$3463> $3462 : () -> <asyncstd/async/async/async: E|ee: E> aa: V)result: -> <async|3582> maybe<3581>: <asyncstd/async/async/async: E|ee: E> maybestd/core/types/maybe: V -> V<aa: V> overridehandler: (() -> <async,discontinue|$3463> $3462) -> <async|$3463> maybe<$3462> handle(actionaction: () -> <async|$3463> $3462) returnreturn: (x : _3473) -> _3474 maybe<_3473>(xx: _3473) Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: _3473) final ctl discontinuediscontinue: () -> <async|$3463> maybe<$3462>() Nothingstd/core/types/Nothing: forall<a> maybe<a>