import type { Either } from "../../Either"; import { NoSuchElementException, PrematureGeneratorExit } from "../../GlobalExceptions"; import type { Option } from "../../Option"; import type { _E, _R } from "../../support/utils"; import { isEither, isOption, isTag } from "../../support/utils"; import type { Has, Tag } from "../../Has"; import type { Task } from "../Task"; import { askService, die, fromEither } from "../Task"; import { fromTask, suspend } from "./constructors"; import { chain_, pure } from "./methods"; import { Stream } from "./model"; export class GenStream { readonly _R!: (_R: R) => void; readonly _E!: () => E; readonly _A!: () => A; constructor(readonly S: Stream) {} *[Symbol.iterator](): Generator, A, any> { return yield this; } } const adapter = (_: any, __?: any) => { if (isOption(_)) { return new GenStream( _._tag === "None" ? fail(__ ? __() : new NoSuchElementException("Stream.gen")) : pure(_.value) ); } else if (isEither(_)) { return new GenStream(fromTask(fromEither(() => _))); } else if (_ instanceof Stream) { return new GenStream(_); } else if (isTag(_)) { return new GenStream(fromTask(askService(_))); } return new GenStream(fromTask(_)); }; export const gen = , A>( f: (i: { (_: Tag): GenStream, never, A>; (_: Option, onNone: () => E): GenStream; (_: Option): GenStream; (_: Either): GenStream; (_: Task): GenStream; (_: Stream): GenStream; }) => Generator ): Stream<_R, _E, A> => suspend(() => { function run(replayStack: any[]): Stream { const iterator = f(adapter as any); let state = iterator.next(); for (let i = 0; i < replayStack.length; i++) { if (state.done) { return fromTask(die(new PrematureGeneratorExit("Stream.gen"))); } state = iterator.next(replayStack[i]); } if (state.done) { return pure(state.value); } return chain_(state.value["S"], (val) => { return run(replayStack.concat([val])); }); } return run([]); });