@tempest/core
Version:
The core of the Tempest Stream Library
91 lines (75 loc) • 2.59 kB
text/typescript
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)
}