/*---------------------------------------------------------------------------
  Copyright 2018-2026, 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 internal primitives

This module defines the primitive asynchronous effects for asynchronous
operations (`:async-await`) and cancelation (`:async-cancel`). The operations
of these effects break the abstraction and should only be used by library 
implementations.

*/
module async/internalstd/async/internal

// ----------------------------------------------------------------------------
// Async effect
// ---------------------------------------------------------------------------- 

// Asynchronous operations have the `:async-await` effect.
// Usually there is only one handler for asynchronous operations at
// the `main` function using the default handler (inserted
// automatically if `main` has the `:async` effect).
pubstd/async/internal/async-await: (E, V) -> V effect async-awaitstd/async/internal/async-await: (E, V) -> V
  // Internal: setup a primitive callback and await its completion. The setup is performed in the handler scope.
  ctl do-await( setupsetup: (evloop : event-loop, resume : (result : await-result<$705>, isdone : bool) -> ioc ()) -> ioc error<dispose-fn> : await-setupstd/async/internal/await-setup: V -> V<aa: V>, async-scopeasync-scope: async-scope : async-scopestd/async/internal/async-scope: V, labellabel: string : stringstd/core/types/string: V ) : await-resultstd/async/internal/await-result: V -> V<aa: V>

  // Internal: Setup a callback to execute `cb` on completion, but return control to the caller immediately
  // after the setup is performed. `cb` is performed in the handler scope.
  fun no-await( setupsetup: (evloop : event-loop, resume : (result : await-result<$773>, isdone : bool) -> ioc ()) -> ioc error<dispose-fn> : await-setupstd/async/internal/await-setup: V -> V<aa: V>, async-scopeasync-scope: async-scope : async-scopestd/async/internal/async-scope: V, labellabel: string : stringstd/core/types/string: V, cbcb: (await-result<$773>) -> 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 ) : (std/core/types/unit: V)std/core/types/unit: V

// The cancelation effect which allows for cancelation of any 
// outstanding asynchronous (interleaved) operations in a cancelation scope (`:async-scope`).
pubstd/async/internal/async-cancel: (E, V) -> V linear effect async-cancelstd/async/internal/async-cancel: (E, V) -> V
  // Internal: The current cancelations scope.
  val async-scope : async-scopestd/async/internal/async-scope: V

  // Internal: Cancel any outstanding async operations of a specific cancelation scope (and all its children)
  fun cancel-scope( scopescope: async-scope : async-scopestd/async/internal/async-scope: V ) : (std/core/types/unit: V)std/core/types/unit: V

  // Internal: Has the current scope ever been canceled?
  fun is-scope-canceled( scopescope: async-scope : async-scopestd/async/internal/async-scope: V ) : boolstd/core/types/bool: V

// Effect to allow `:ioc` operations to execute in the scope of the handler.
pubstd/async/internal/async-ioc: (E, V) -> V linear effect async-iocstd/async/internal/async-ioc: (E, V) -> V
  // Internal: perform an I/O operation in the outer async handler
  fun async-ioc( actionaction: () -> ioc $1235 : () -> iocstd/core/ioc: E aa: V ) : aa: V

  // Internal: perform an I/O operation in the outer async handler in the next event loop tick
  fun async-schedule-ioc( actionaction: () -> ioc () : () -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V ) : (std/core/types/unit: V)std/core/types/unit: V

  
// Function that disposes any resources for an await call (i.e. `clearTimeout`)
// and should ensure that any primitive callback is no longer called.
pub alias dispose-fnstd/async/internal/dispose-fn: V = () -> iocstd/core/ioc: E (std/core/types/unit: V)std/core/types/unit: V

// Abstract type for an external event loop. 
pub alias event-loopstd/async/internal/event-loop: V = anystd/core/types/any: V

// A function that will setup a primitive await. It gets passed the current event loop
// and a resumption function, and returns either an error or a dispose function.
// The resumption gets the `:await-result` (cancel, exception, or regular result) and
// whether this is the last time the resumption is called (`isdone`).
pub alias await-setupstd/async/internal/await-setup: V -> V<aa: V> = (evloop : event-loopstd/async/internal/event-loop: V, resume : (result:await-resultstd/async/internal/await-result: V -> V<aa: V>, isdone:boolstd/core/types/bool: 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>

// An await result is either canceled, an exception, or a regular return value.
pub type await-resultstd/async/internal/await-result: V -> V<aa: V>
  Cancelstd/async/internal/Cancel: forall<a> await-result<a>
  Exceptionstd/async/internal/Exception: forall<a> (exn : exception) -> await-result<a>( exn: exceptionstd/core/exn/exception: V )
  Resultstd/async/internal/Result: forall<a> (value : a) -> await-result<a>( value: aa: V )

// ----------------------------------------------------------------------------
// Cancelation Scopes
// ----------------------------------------------------------------------------

// A async-scope has an ID, plus a list of child IDs.
// Every created async-scope has a unique ID
alias scope-idstd/async/internal/scope-id: V = intstd/core/types/int: V

// An abstract cancelation async-scope
abstract value type async-scopestd/async/internal/async-scope: V
  Scopestd/async/internal/Scope: (scopes : list<scope-id>) -> async-scope( scopesstd/async/internal/async-scope/scopes: (async-scope) -> list<scope-id> : liststd/core/types/list: V -> V<scope-idstd/async/internal/scope-id: V> )

pub fun async-scope/showstd/async/internal/async-scope/show: (async-scope) -> string( Scopestd/async/internal/Scope: (scopes : list<scope-id>) -> async-scope(idsids: list<scope-id>) : async-scopestd/async/internal/async-scope: V )result: -> total string : stringstd/core/types/string: V
  idsids: list<scope-id>.mapstd/core/list/map: (xs : list<scope-id>, f : (scope-id) -> string) -> list<string>(showstd/core/int/show: (i : int) -> string).joinstd/core/list/joinsep/join: (xs : list<string>, sep : string) -> string("<"literal: string
count= 1
) // A scope is the chain starting with the current scope, including parent scopes up to the root scope-id pub val root-scopestd/async/internal/root-scope: async-scope = Scopestd/async/internal/Scope: (scopes : list<scope-id>) -> async-scope([std/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
]std/core/types/Nil: forall<a> list<a>
) pub fun new-child-scope-iocstd/async/internal/new-child-scope-ioc: (async-scope) -> ioc async-scope( Scopestd/async/internal/Scope: (scopes : list<scope-id>) -> async-scope(idsids: list<scope-id>) : async-scopestd/async/internal/async-scope: V )result: -> ioc async-scope : iocstd/core/ioc: E async-scopestd/async/internal/async-scope: V val cidcid: int = uniquestd/core/unique: () -> ioc int()+std/core/int/(+): (x : int, y : int) -> ioc int1literal: int
dec = 1
hex8 = 0x01
bit8 = 0b00000001
Scopestd/async/internal/Scope: (scopes : list<scope-id>) -> async-scope(Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(cidcid: int,idsids: list<scope-id>)
) pub fun new-child-scopestd/async/internal/new-child-scope: (scope : async-scope) -> async-ioc async-scope( scopescope: async-scope : async-scopestd/async/internal/async-scope: V )result: -> async-ioc async-scope : async-iocstd/async/internal/async-ioc: (E, V) -> V async-scopestd/async/internal/async-scope: V async-iocstd/async/internal/async-ioc: (action : () -> ioc async-scope) -> async-ioc async-scope{ new-child-scope-iocstd/async/internal/new-child-scope-ioc: (async-scope) -> ioc async-scope(scopescope: async-scope) } fun scope-idstd/async/internal/scope-id: (async-scope) -> scope-id( Scopestd/async/internal/Scope: (scopes : list<scope-id>) -> async-scope(idsids: list<scope-id>) )result: -> total scope-id : scope-idstd/async/internal/scope-id: V idsids: list<scope-id>.headstd/core/list/head: (xs : list<scope-id>, default : scope-id) -> scope-id(0literal: int
dec = 0
hex8 = 0x00
bit8 = 0b00000000
) pub fun parentstd/async/internal/parent: (async-scope) -> async-scope( Scopestd/async/internal/Scope: (scopes : list<scope-id>) -> async-scope(idsids: list<scope-id>) : async-scopestd/async/internal/async-scope: V )result: -> total async-scope : async-scopestd/async/internal/async-scope: V match idsids: list<scope-id> Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>(_,iddidd: list<scope-id> as Consstd/core/types/Cons: forall<a> (head : a, tail : list<a>) -> list<a>) -> Scopestd/async/internal/Scope: (scopes : list<scope-id>) -> async-scope(iddidd: list<scope-id>) _ -> root-scopestd/async/internal/root-scope: async-scope // Is `async-scope` equal to, or a child async-scope of `root`? pub fun (<=)std/async/internal/(<=): (async-scope, root : async-scope) -> bool( Scopestd/async/internal/Scope: (scopes : list<scope-id>) -> async-scope(idsids: list<scope-id>) : async-scopestd/async/internal/async-scope: V, rootroot: async-scope : async-scopestd/async/internal/async-scope: V )result: -> total bool : boolstd/core/types/bool: V val sidsid: scope-id = rootroot: async-scope.scope-idstd/async/internal/scope-id: (async-scope) -> scope-id idsids: list<scope-id>.findstd/core/list/find: (xs : list<scope-id>, pred : (scope-id) -> bool) -> maybe<scope-id>(fnfn: (x : scope-id) -> bool(xx: scope-id) xx: scope-id ==std/core/int/(==): (x : int, y : int) -> bool sidsid: scope-id).is-juststd/core/types/is-just: (maybe : maybe<scope-id>) -> bool // O(1). Are the scopes equal? pub fun async-scope/(==)std/async/internal/async-scope/(==): (s1 : async-scope, s2 : async-scope) -> bool(s1s1: async-scope : async-scopestd/async/internal/async-scope: V, s2s2: async-scope : async-scopestd/async/internal/async-scope: V )result: -> total bool : boolstd/core/types/bool: V s1s1: async-scope.scope-idstd/async/internal/scope-id: (async-scope) -> scope-id ==std/core/int/(==): (x : int, y : int) -> bool s2s2: async-scope.scope-idstd/async/internal/scope-id: (async-scope) -> scope-id