import { HaltError } from './halt-error' ; import { createRunLoop , RunLoop } from './run-loop' ; export type State = 'pending' | 'errored' | 'completed' | 'halted' ; export type Value < T > = { state : 'errored' ; error : Error ; } | { state : 'completed' ; value : T ; } | { state : 'halted' ; } ; export interface Consumer < T > { ( value ) : void ; } /**
 * `FutureLike` is a slimmed down interface, similar to `PromiseLink` which
 * does not make equally strong requirements on the implementor. In Effection,
 *  Task implements `FutureLike`, but not {@linkcode Future}.
 *
 * See [the Futures guide](https://frontside.com/effection/docs/guides/futures)
 * for a more detailed description of futures and how they work.
  export interface FutureLike < T > { consume ( consumer ) : void ; } /**
 * A Future represents a value which may or may not be available yet. It is
 * similar to a JavaScript Promise, except that it can resolve synchronously.
 *
 * See [the Futures guide](https://frontside.com/effection/docs/guides/futures)
 * for a more detailed description of futures and how they work.
 *
 * A Future may resolve to *three* different states. A Future can either become
 * `completed` with a value, it can become `errored` with an Error or it can
 * become `halted`, meaning it was prematurely cancelled.
 *
 * A Future can be created via the  createFuture function, or via the
 * The `resolve`, `reject` and `halt` functions on  Future .
 *
 * See also the slimmed down  FutureLike interface.
  export interface Future < T > extends Promise < T > , FutureLike < T > { state : State ; } export interface NewFuture < T > { future : Future < T > ; produce ( value ) : void ; resolve ( value ) : void ; reject ( error ) : void ; halt ( ) : void ; } /**
 * Create a new Future. This returns an object which contains the future itself
 * as well as a function to produce a value for the future, and also shortcuts
 * to resolve/reject/halt the future.
 *
 * ### Example
 *
 * ```typescript
 * import { createFuture } from 'effection';
 *
 * let { future, produce } = createFuture<number>();
 *
 * // later...
 * produce({ state: 'completed', value: 100 });
 *
 * future.consume((value) => console.log(value)) // => { state: 'completed', value: 100 }
 * ```
 *
 * ### Example using shortcut
 *
 * ```typescript
 * import { createFuture } from 'effection';
 *
 * let { future, resolve } = createFuture<number>();
 *
 * // later...
 * resolve(100);
 *
 * future.consume((value) => console.log(value)) // => { state: 'completed', value: 100 }
 * ```
 */ export function createFuture < T > ( ) { return createFutureOnRunLoop ( createRunLoop ( 'future' ) ) ; } export function createFutureOnRunLoop < T > ( runLoop ) { let consumers = [ ] ; let result ; function consume ( consumer ) { consumers . push ( consumer ) ; runLoop . run ( run ) ; } function run ( ) { if ( result ) { while ( true ) { let consumer = consumers . shift ( ) ; if ( consumer ) { consumer ( result ) ; } else { break ; } } } } function produce ( value ) { if ( ! result ) { result = value ; runLoop . run ( run ) ; } } let promise ; function getPromise ( ) { return promise || ( promise = new Promise < T > ( ( resolve , reject ) => { consume ( ( value ) => { if ( value . state === 'completed' ) { resolve ( value . value ) ; } else if ( value . state === 'errored' ) { reject ( value . error ) ; } else if ( value . state === 'halted' ) { reject ( new HaltError ( ) ) ; } } ) ; } ) ) ; } return { produce , future : { get state ( ) { return result ?. state || 'pending' ; } , consume , then : ( ... args ) => getPromise ( ) . then ( ... args ) , catch : ( ... args ) => getPromise ( ) . catch ( ... args ) , finally : ( ... args ) => getPromise ( ) . finally ( ... args ) , [ Symbol . toStringTag ] : '[continuation]' } , resolve : ( value ) => produce ( { state : 'completed' , value } ) , reject : ( error ) => produce ( { state : 'errored' , error } ) , halt : ( ) => produce ( { state : 'halted' } ) } ; } /**
 * Namespace for `Future` functions to create resolved futures.
 *
 * See [Future](./interfaces/Future.html).
 */ export const Future = { param value typeParam resolve < T > ( value ) { let { future , resolve } = createFuture < T > ( ) ; resolve ( value ) ; return future ; } , param error typeParam reject < T = unknown > ( error ) { let { future , reject } = createFuture < T > ( ) ; reject ( error ) ; return future ; } , typeParam halt < T = unknown > ( ) { let { future , halt } = createFuture < T > ( ) ; halt ( ) ; return future ; } } ;