import { None } from '../option/none' ; import { Option } from '../option/option' ; import { Try } from '../try/try' ; /**
 * A Future represents a value which may or may not be available.  It may be asynchronously filled
 * in the future.
 */ class Future < A > { static create < A > ( value ) { const isPromise = ( value ) : value is Promise < A > => { return value instanceof Promise ; } ; if ( isPromise ( value ) ) { return new Future ( value as Promise < A > ) ; } else { return new Future ( Promise . resolve ( value ) ) ; } } protected promise_ : Promise < A > ; protected value_ : Option < Try < A > > ; get isCompleted ( ) : boolean { return this . value . isDefined ; } get promise ( ) : Promise < A > { return this . promise_ ; } get value ( ) : Option < Try < A > > { return this . value_ ; } protected constructor ( promise ) { this . value_ = None ; this . promise_ = promise . then ( ( value ) : A => { this . value_ = Option ( Try ( ( ) => value ) ) ; return value ; } ) . catch ( ( error ) : Promise < A > => { this . value_ = Option ( Try ( ( ) => { throw error ; } ) ) ; return promise ; } ) ; } filter ( predicate ) { return new Future ( new Promise ( ( resolve , reject ) : void => { this . promise . then ( ( value ) : void => { if ( predicate ( value ) ) { resolve ( value ) ; } else { reject ( new Error ( 'Future.filter predicate is not satisfied' ) ) ; } } ) . catch ( ( error ) : void => { reject ( error ) ; } ) ; } ) ) ; } flatMap < B > ( mapper ) { return new Future ( new Promise ( ( resolve , reject ) : void => { this . promise . then ( ( value ) : void => { try { mapper ( value ) . promise . then ( ( value ) : void => { resolve ( value ) ; } ) . catch ( ( error ) : void => { reject ( error ) ; } ) ; } catch ( error ) { reject ( error as Error ) ; } } ) . catch ( ( error ) : void => { reject ( error ) ; } ) ; } ) ) ; } foreach < B > ( run ) { this . promise . then ( ( value ) : void => { run ( value ) ; } ) . catch ( ( error ) : void => { } ) ; } map < B > ( mapper ) { return new Future ( this . promise . then ( ( value ) : B => { return mapper ( value ) ; } ) . catch ( ( error ) : Promise < B > => { throw error ; } ) ) ; } onComplete < B > ( run ) { this . promise . then ( ( value ) : void => { run ( Try ( ( ) => value ) ) ; } ) . catch ( ( error ) : void => { run ( Try ( ( ) => { throw error ; } ) ) ; } ) ; } recover < B , A extends B > ( this , f ) { return new Future ( new Promise ( ( resolve , reject ) : void => { this . promise . then ( ( value ) : void => { resolve ( value ) ; } ) . catch ( ( error ) : void => { try { resolve ( f ( error ) ) ; } catch ( error ) { reject ( error as Error ) ; } } ) ; } ) ) ; } recoverWith < B , A extends B > ( this , f ) { return new Future ( new Promise ( ( resolve , reject ) : void => { this . promise . then ( ( value ) : void => { resolve ( value ) ; } ) . catch ( ( error ) : void => { try { f ( error ) . foreach ( ( b ) : void => { resolve ( b ) ; } ) ; } catch ( error ) { reject ( error as Error ) ; } } ) ; } ) ) ; } zip < B > ( that ) { return this . flatMap ( ( value ) => that . map ( ( thatValue ) => [ value , thatValue ] as [ A , B ] ) ) ; } } export { Future } ;