import { SinkInternal } from "@effect/core/stream/Sink/operations/_internal/SinkInternal" /** * A sink that folds its inputs with the provided function, termination * predicate and initial state. * * @tsplus static effect/core/stream/Sink.Ops fold */ export function fold( z: S, cont: Predicate, f: (s: S, input: In) => S ): Sink { return Sink.suspend(new SinkInternal(reader(z, cont, f))) } function reader( z: S, cont: Predicate, f: (s: S, input: In) => S ): Channel, unknown, never, Chunk, S> { return !cont(z) ? Channel.succeed(z) : Channel.readWith( (chunk: Chunk) => { const [nextS, leftovers] = foldChunkSplit(z, chunk, cont, f) return leftovers.isNonEmpty ? Channel.write(leftovers).as(nextS) : reader(nextS, cont, f) }, (err) => Channel.fail(err), () => Channel.succeed(z) ) } function foldChunkSplit( z: S, chunk: Chunk, cont: Predicate, f: (s: S, input: In) => S ): readonly [S, Chunk] { return foldInternal(z, chunk, cont, f, 0, chunk.length) } function foldInternal( z: S, chunk: Chunk, cont: Predicate, f: (s: S, input: In) => S, index: number, length: number ): readonly [S, Chunk] { if (index === length) { return [z, Chunk.empty()] } const z1 = f(z, chunk.unsafeGet(index)) return cont(z1) ? foldInternal(z1, chunk, cont, f, index + 1, length) : [z1, chunk.drop(index + 1)] }