import { Err, Ok, Result } from '../classes/Result'; export const ITERATOR_EXHAUSTED = Symbol.for('ITERATOR_EXHAUSTED'); export type SyncGenerator = () => I | Result; export type SyncStepper = (previous: I) => I | Result; export type SyncIterator = (input: I) => O | Result; export type SyncValidator = (output: O) => boolean | Result; export function iterateSync( genfn: SyncGenerator, iterator: SyncIterator, validator: SyncValidator ): Result; export function iterateSync( iterable: Iterable, iterator: SyncIterator, validator: SyncValidator ): Result; export function iterateSync( init: SyncGenerator, step: SyncStepper, iterator: SyncIterator, validator: SyncValidator ): Result; export function iterateSync( ...args: | [SyncGenerator, SyncIterator, SyncValidator] | [Iterable, SyncIterator, SyncValidator] | [ SyncGenerator, SyncStepper, SyncIterator, SyncValidator ] ): Result { if (args.length === 4) { return iterateSyncResultWrapper(...args); } if (Symbol.iterator in args[0]) { return iterateSyncIterableWrapper(args[0], args[1], args[2]); } return iterateSyncResultWrapper(args[0], args[0], args[1], args[2]); } export function iterateSyncIterableWrapper( iterable: Iterable, iterator: SyncIterator, validator: SyncValidator ): Result { const reader = iterable[Symbol.iterator](); const next = () => { const { done, value } = reader.next(); if (done && value === void 0) { throw ITERATOR_EXHAUSTED; } return value; }; return iterateSyncResultWrapper(next, next, iterator, validator); } export function iterateSyncResultWrapper( init: SyncGenerator, step: SyncStepper, iterator: SyncIterator, validator: SyncValidator = () => true ): Result { try { return Ok(iterateSyncImpl(init, step, iterator, validator)); } catch (error) { return Err(error); } } export function iterateSyncImpl( init: SyncGenerator, step: SyncStepper, iterator: SyncIterator, validator: SyncValidator = () => true ): O { for ( let input = Result.unwrap(init()); ; input = Result.unwrap(step(input)) ) { const output = Result.unwrap(iterator(input)); const valid = Result.unwrap(validator(output)); if (valid) { return output; } } } for (const _ of [ iterateSync, iterateSyncIterableWrapper, iterateSyncResultWrapper, iterateSyncImpl, ]) { Object.defineProperties(_, { default: { get: () => iterateSync }, iterateSync: { get: () => iterateSync }, iterateSyncIterableWrapper: { get: () => iterateSyncIterableWrapper }, iterateSyncResultWrapper: { get: () => iterateSyncResultWrapper }, iterateSyncImpl: { get: () => iterateSyncImpl }, }); }