import { AsyncIterableX } from '../asynciterablex' ; import { IRefCountList , MaxRefCountList , RefCountList , } from '../../iterable/operators/_refcountlist' ; import { create } from '../create' ; import { OperatorAsyncFunction } from '../../interfaces' ; import { throwIfAborted } from '../../aborterror' ; export class MemoizeAsyncBuffer < T > extends AsyncIterableX < T > { protected _source : AsyncIterator < T > ; protected _buffer : IRefCountList < T > ; protected _shared : Promise < IteratorResult < T > > | null ; protected _error : any ; protected _stopped : boolean ; constructor ( source , buffer ) { super ( ) ; this . _error = null ; this . _shared = null ; this . _stopped = false ; this . _source = source ; this . _buffer = buffer ; } [ Symbol . asyncIterator ] ( signal ? ) { throwIfAborted ( signal ) ; return this . _getIterable ( 0 ) ; } protected async * _getIterable ( offset = 0 ) { let i = offset - 1 ; let done = false ; const buffer = this . _buffer ; try { do { if ( ++ i < buffer . count ) { yield buffer . get ( i ) ; continue ; } if ( this . _stopped ) { throw this . _error ; } if ( this . _shared === null ) { this . _shared = this . _source . next ( ) . then ( ( r ) => { this . _shared = null ; if ( ! r . done ) { buffer . push ( r . value ) ; } return r ; } ) ; } ( { done } = await this . _shared . catch ( ( e ) => { this . _error = e ; this . _stopped = true ; throw e ; } ) ) ; if ( ! done ) { yield buffer . get ( i ) ; } } while ( ! done ) ; } finally { buffer . done ( ) ; } } } template TSource param { number } readerCount returns { OperatorAsyncFunction < TSource , TSource > } export function memoize < TSource > ( readerCount ? ) ; template TSource template TResult param { number } readerCount param { ( value : AsyncIterableX < TSource > ) => AsyncIterable < TResult > } selector returns { OperatorAsyncFunction < TSource , TResult > } export function memoize < TSource , TResult > ( readerCount ? , selector ? ) ; template TSource template TResult param { number } readerCount param { ( value : AsyncIterable < TSource > ) => AsyncIterable < TResult > } selector returns { ( OperatorAsyncFunction < TSource , TSource | TResult > ) } export function memoize < TSource , TResult = TSource > ( readerCount = - 1 , selector ? ) { return function memoizeOperatorFunction ( source ) : AsyncIterableX < TSource | TResult > { if ( ! selector ) { return readerCount === - 1 ? new MemoizeAsyncBuffer < TSource > ( source [ Symbol . asyncIterator ] ( ) , new MaxRefCountList < TSource > ( ) ) : new MemoizeAsyncBuffer < TSource > ( source [ Symbol . asyncIterator ] ( ) , new RefCountList < TSource > ( readerCount ) ) ; } return create < TSource | TResult > ( ( ) => selector ! ( memoize < TSource > ( readerCount ) ( source ) ) [ Symbol . asyncIterator ] ( ) ) ; } ; }