import * as assert from "@esfx/internal-assert" ; class EmptyIterable < T > implements Iterable < T > { * [ Symbol . iterator ] ( ) { } } category export function empty < T > ( ) { return new EmptyIterable < T > ( ) ; } export interface ConsumeOptions { /** Indicates whether iterated elements should be cached for subsequent iterations. */ cacheElements ? : boolean ; /** Indicates whether to leave the iterator open when the iterable returns. */ leaveOpen ? : boolean ; } class ConsumeIterable < T > implements Iterable < T > { private _iterator : Iterator < T > | undefined ; private _cache ? : T [ ] ; private _leaveOpen : boolean ; constructor ( iterator , cacheElements , leaveOpen ) { this . _iterator = iterator ; this . _cache = cacheElements ? [ ] : undefined ; this . _leaveOpen = leaveOpen ; } * [ Symbol . iterator ] ( ) { let offset = 0 ; try { for ( ; ; ) { if ( this . _cache && offset < this . _cache . length ) { yield this . _cache [ offset ++ ] ; continue ; } else if ( this . _iterator ) { const { done , value } = this . _iterator . next ( ) ; if ( ! done ) { if ( this . _cache ) this . _cache . push ( value ) ; yield value ; offset ++ ; continue ; } this . _iterator = undefined ; } return ; } } finally { if ( ! this . _leaveOpen ) { this . _iterator ?. return ?. ( ) ; } } } } param iterator category export function consume < T > ( iterator , options = { } ) { const { cacheElements = false , leaveOpen = false } = options ; assert . mustBeIterator ( iterator , "iterator" ) ; assert . mustBeBoolean ( cacheElements , "cacheElements" ) ; return new ConsumeIterable ( iterator , cacheElements , leaveOpen ) ; } class ContinuousIterable < T > implements Iterable < T > { private _value : T ; constructor ( value ) { this . _value = value ; } * [ Symbol . iterator ] ( ) { const value = this . _value ; for ( ; ; ) { yield value ; } } } param value category export function continuous < T > ( value ) { return new ContinuousIterable ( value ) ; } class GenerateIterable < T > implements Iterable < T > { private _count : number ; private _generator : ( offset : number ) => T ; constructor ( count , generator ) { this . _count = count ; this . _generator = generator ; } * [ Symbol . iterator ] ( ) { const count = this . _count ; const generator = this . _generator ; for ( let i = 0 ; i < count ; i ++ ) { yield generator ( i ) ; } } } param count param generator category export function generate < T > ( count , generator ) { assert . mustBePositiveFiniteNumber ( count , "count" ) ; assert . mustBeFunction ( generator , "generator" ) ; return new GenerateIterable ( count , generator ) ; } class OnceIterable < T > implements Iterable < T > { private _value : T ; constructor ( value ) { this . _value = value ; } * [ Symbol . iterator ] ( ) { yield this . _value ; } } param value category export function once < T > ( value ) { return new OnceIterable ( value ) ; } class RepeatIterable < T > implements Iterable < T > { private _value : T ; private _count : number ; constructor ( value , count ) { this . _value = value ; this . _count = count ; } * [ Symbol . iterator ] ( ) { const value = this . _value ; for ( let count = this . _count ; count > 0 ; -- count ) { yield value ; } } } param value param count category export function repeat < T > ( value , count ) { assert . mustBePositiveFiniteNumber ( count , "count" ) ; return new RepeatIterable ( value , count ) ; } class RangeIterable implements Iterable < number > { private _start : number ; private _end : number ; private _increment : number ; constructor ( start , end , increment ) { this . _start = start ; this . _end = end ; this . _increment = increment ; } * [ Symbol . iterator ] ( ) { const start = this . _start ; const end = this . _end ; const increment = this . _increment ; if ( start <= end ) { for ( let i = start ; i <= end ; i += increment ) { yield i ; } } else { for ( let i = start ; i >= end ; i -= increment ) { yield i ; } } } } param start param end param increment category export function range ( start , end , increment = 1 ) { assert . mustBeFiniteNumber ( start , "start" ) ; assert . mustBeFiniteNumber ( end , "end" ) ; assert . mustBePositiveNonZeroFiniteNumber ( increment , "increment" ) ; return new RangeIterable ( start , end , increment ) ; }