import { AtomicPromise, Internal, internal } from './promise'; const state = Symbol('spica/future::state'); export class Future extends Promise { public static get [Symbol.species]() { return Promise; } constructor(private readonly strict: boolean = true) { let resolve!: (v: T | PromiseLike) => void; super(r => resolve = r); this[state] = { pending: true, resolve, }; } private readonly [state]: { pending: boolean, resolve: (value: T | PromiseLike) => void, }; private bind$(value: T | PromiseLike): Promise; private bind$(this: Future, value?: T | PromiseLike): Promise; private bind$(value: T | PromiseLike): Promise { if (this[state].pending) { this[state].pending = false; this[state].resolve(value); } else if (this.strict) { throw new Error(`Spica: Future: Cannot rebind the value`); } return this; } public get bind(): Future['bind$'] { return value => this.bind$(value!); } } export interface AtomicFuture extends AtomicPromise { } export class AtomicFuture implements AtomicPromise { public readonly [Symbol.toStringTag]: string = 'Promise'; constructor(private readonly strict: boolean = true) { } public readonly [internal] = new Internal(); private bind$(value: T | PromiseLike): AtomicPromise; private bind$(this: AtomicFuture, value?: T | PromiseLike): AtomicPromise; private bind$(value: T | PromiseLike): AtomicPromise { if (this[internal].isPending()) { this[internal].resolve(value); } else if (this.strict) { throw new Error(`Spica: AtomicFuture: Cannot rebind the value`); } return this; } public get bind(): AtomicFuture['bind$'] { return value => this.bind$(value!); } } AtomicFuture.prototype.then = AtomicPromise.prototype.then; AtomicFuture.prototype.catch = AtomicPromise.prototype.catch; AtomicFuture.prototype.finally = AtomicPromise.prototype.finally;