import { Disposable } from '@typed/disposable' import { Either, Left, Right } from '@typed/either' import { Env, Pure, Resume } from '@typed/env' import { Arity1, pipe } from '@typed/lambda' // Futures should only ever contain 1 value export type Future = Env> export type PureFuture = Pure> export namespace Future { export const of = (value: B): PureFuture => Pure.of(Either.of(value)) export const create = ( fn: ( reject: Arity1, resolve: Arity1, environment: E, ) => Disposable, ): Future => (e: E) => Resume.create((cb) => { const ifNotResolved = createIfNotResolved() return fn(ifNotResolved(pipe(Left.of, cb)), ifNotResolved(pipe(Right.of, cb)), e) }) export const fromPromise = (promise: () => PromiseLike): PureFuture => create((reject, resolve) => { const disposable = Disposable.lazy() promise().then( (a) => disposable.addDisposable(resolve(a)), (e) => disposable.addDisposable(reject(e)), ) return disposable }) } function createIfNotResolved() { let resolved = false return (fn: (value: A) => Disposable) => { return (value: A) => { if (!resolved) { resolved = true return fn(value) } return Disposable.None } } }