UNPKG

nice-grpc-web

Version:

A Browser gRPC library that is nice to you

87 lines (72 loc) 2.07 kB
// Credit: IxJS authors // https://github.com/ReactiveX/IxJS/blob/v4.5.1/src/asynciterable/asyncsink.ts // This implementation has a slight change: it silently ignores items pushed // after end instead of throwing an error. const ARRAY_VALUE = 'value'; const ARRAY_ERROR = 'error'; interface AsyncSinkItem<T> { type: string; value?: T; error?: any; } interface AsyncResolver<T> { resolve: (value: T | PromiseLike<T>) => void; reject: (reason: any) => void; } /** @internal */ export class AsyncSink<TSource> implements AsyncIterableIterator<TSource> { private _ended: boolean; private _values: AsyncSinkItem<TSource>[]; private _resolvers: AsyncResolver<IteratorResult<TSource>>[]; constructor() { this._ended = false; this._values = []; this._resolvers = []; } [Symbol.asyncIterator]() { return this; } write(value: TSource) { this._push({type: ARRAY_VALUE, value}); } error(error: any) { this._push({type: ARRAY_ERROR, error}); } private _push(item: AsyncSinkItem<TSource>) { if (this._ended) { return; } if (this._resolvers.length > 0) { const {resolve, reject} = this._resolvers.shift()!; if (item.type === ARRAY_ERROR) { reject(item.error!); } else { resolve({done: false, value: item.value!}); } } else { this._values.push(item); } } next() { if (this._values.length > 0) { const {type, value, error} = this._values.shift()!; if (type === ARRAY_ERROR) { return Promise.reject(error); } else { return Promise.resolve({done: false, value} as IteratorResult<TSource>); } } if (this._ended) { return Promise.resolve({done: true} as IteratorResult<TSource>); } return new Promise<IteratorResult<TSource>>((resolve, reject) => { this._resolvers.push({resolve, reject}); }); } end() { while (this._resolvers.length > 0) { this._resolvers.shift()!.resolve({done: true} as IteratorResult<TSource>); } this._ended = true; } }