UNPKG

@tempest/core

Version:

The core of the Tempest Stream Library

91 lines (75 loc) 2.59 kB
import { Source, Scheduler, Disposable, Sink } from './interfaces' import { defaultScheduler } from './scheduler/defaultScheduler' export function withDefaultScheduler<T> (f: (x: T) => any, source: Source<T>) { return withScheduler<T>(f, source, defaultScheduler) } export function withScheduler<T> (f: (x: T) => any, source: Source<T>, scheduler: Scheduler): Promise<T> { return new Promise<T>((resolve, reject) => { runSource<T>(f, source, scheduler, resolve, reject) }) } export function runSource<T> (f: (x: T) => any, source: Source<T>, scheduler: Scheduler, end: (x?: T) => any, error: (e: Error) => any) { const disposable = new SettableDisposable<T>() const observer = new Drain<T>(f, end, error, disposable) disposable.setDisposable(source.run(observer, scheduler)) } class SettableDisposable<T> implements Disposable<T> { private disposable: Disposable<T> private disposed: boolean private _resolve: (x: Promise<T> | void) => any private _result: any constructor () { this.disposable = void 0 this.disposed = false this._resolve = void 0 const self = this this._result = new Promise<Promise<T> | void>((resolve) => { self._resolve = resolve }) } dispose () { if (this.disposed) return this._result this.disposed = true if (this.disposable) { this._result = this.disposable.dispose() } return this._result } setDisposable (disposable: Disposable<T>) { if (this.disposable !== void 0) { throw new Error('Disposable can only be set one time') } this.disposable = disposable if (this.disposed) { this._resolve(disposable.dispose()) } } } class Drain<T> implements Sink<T> { private active: boolean = true constructor (private _event: (x: T) => any, private _end: (x?: T) => any, private _error: (e: Error) => any, private disposable: Disposable<T>) { } event (time: number, value: T) { if (!this.active) return this._event(value) } error (time: number, err: Error) { if (!this.active) return this.active = false disposeThen<any>(this._error, this._error, this.disposable, err) } end (time: number, value?: T) { if (!this.active) return this.active = false disposeThen<T>(this._error, this._error, this.disposable, value) } } function disposeThen<T>(end: (x: any) => any, error: (x: any) => any, disposable: Disposable<T>, value: T) { Promise.resolve<any>(disposable.dispose()).then(() => { end(value) }, error) }