You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

63 lines
1.7 KiB

import {Collection} from './Collection.ts'
export type MaybeIterationItem<T> = { done: boolean, value?: T }
export type ChunkCallback<T> = (items: Collection<T>) => any
export class StopIteration extends Error {}
export abstract class Iterable<T> {
protected index = 0
abstract async at_index(i: number): Promise<T>
abstract async from_range(start: number, end: number): Promise<Collection<T>>
abstract async count(): Promise<number>
abstract clone(): Iterable<T>
public async next(): Promise<MaybeIterationItem<T>> {
const i = this.index
if ( i >= await this.count() ) {
return { done: true }
}
this.index = i + 1
return { done: false, value: await this.at_index(i) }
}
[Symbol.asyncIterator]() {
return this
}
public async chunk(size: number, callback: ChunkCallback<T>) {
const total = await this.count()
while ( this.index < total ) {
const items = await this.from_range(this.index, this.index + size - 1)
try {
await callback(items)
} catch ( error ) {
if ( error instanceof StopIteration ) break
else throw error
}
this.index += size
}
}
public async seek(index: number) {
if ( index < 0 ) throw new TypeError('Cannot seek to negative index.')
else if ( index >= await this.count() ) throw new TypeError('Cannot seek past last item.')
this.index = index
}
public async peek(): Promise<T | undefined> {
if ( this.index + 1 >= await this.count() ) return undefined
else return this.at_index(this.index + 1)
}
public async reset() {
this.index = 0
}
}