import { IterResult, Nullable } from '../utils' export interface IMapAccess { nextKeySeed>(seed: K): IteratorResult nextValueSeed>(seed: V): IteratorResult nextEntrySeed, V extends Deserialize>(kseed: K, vseed: V): IteratorResult<[TK, TV]> nextKey(): IteratorResult nextValue(): IteratorResult nextEntry(): IteratorResult<[K, V]> sizeHint?(): Nullable entries>(seed?: K): Iterator values>(seed?: V): Iterator entries, V extends Deserialize>(kseed: K, vseed: V): Iterator<[TK, TV]> [Symbol.iterator](): Iterator<[K, V]> } export abstract class MapAccess { abstract nextKeySeed>(seed: K): IteratorResult abstract nextValueSeed>(seed: V): IteratorResult nextEntrySeed, V extends Deserialize>(kseed: K, vseed: V): IteratorResult<[TK, TV]> { const key = this.nextKeySeed(kseed) as IteratorResult if (!key.done) { const value = this.nextValueSeed(vseed) as IteratorResult if (!value.done) { return IterResult.Next([key.value, value.value]) } } return IterResult.Done() } abstract nextKey(): IteratorResult abstract nextValue(): IteratorResult nextEntry(): IteratorResult<[K, V]> { const key = this.nextKey() as IteratorResult if (!key.done) { const value = this.nextValue() as IteratorResult if (!value.done) { return IterResult.Next([key.value, value.value]) } } return IterResult.Done() } private *generate(next: () => IteratorResult): Iterator { let item while ((item = next()) && !item.done) { yield item.value } } keys>(seed?: K): Iterator { return this.generate( seed == null ? this.nextKey.bind(this) : this.nextKeySeed.bind(this, seed) as any ) } values>(seed?: V): Iterator { return this.generate( seed == null ? this.nextValue.bind(this) : this.nextValueSeed.bind(this, seed) as any ) } entries, V extends Deserialize>(kseed?: K, vseed?: V): Iterator<[TK, TV]> { return this.generate( kseed == null || vseed == null ? this.nextEntry.bind(this) : this.nextEntrySeed.bind(this, kseed, vseed) as any ) } [Symbol.iterator](): Iterator { return this.entries() as Iterator } } export interface IIterableAccess { nextElement(): IteratorResult sizeHint?(): Nullable [Symbol.iterator](): Iterator } export abstract class IterableAccess implements IIterableAccess { abstract nextElement(): IteratorResult *[Symbol.iterator](): Iterator { return { next: this.nextElement } } } const VisitorMethods = Object.freeze([ 'visitBoolean', 'visitNumber', 'visitBigInt', 'visitString', 'visitSymbol', 'visitNull', 'visitObject', 'visitIterable' ] as const) export function isVisitor(visitor: any): visitor is IVisitor { return VisitorMethods.every(method => method in visitor) } export interface IVisitor { visitBoolean(value: boolean): T visitNumber(value: number): T visitBigInt(value: bigint): T visitString(value: string): T visitSymbol(value: symbol): T visitNull(): T visitObject(access: IMapAccess): T visitIterable(access: IIterableAccess): T } export interface IDeserializer { deserializeAny(visitor: Partial>): T deserializeBoolean(visitor: Partial>): T deserializeNumber(visitor: Partial>): T deserializeBigInt(visitor: Partial>): T deserializeString(visitor: Partial>): T deserializeSymbol(visitor: Partial>): T deserializeNull(visitor: Partial>): T deserializeObject(visitor: Partial>): T deserializeIterable(visitor: Partial>): T deserializeFunction(visitor: Partial>): T } export interface Deserialize { (deserializer: IDeserializer): T }