import {
concreteStream,
StreamInternal
} from "@effect/core/stream/Stream/operations/_internal/StreamInternal"
/**
* Splits elements based on a predicate.
*
* @tsplus static effect/core/stream/Stream.Aspects split
* @tsplus pipeable effect/core/stream/Stream split
*/
export function split(f: Predicate) {
return (self: Stream): Stream> => {
concreteStream(self)
return new StreamInternal(self.channel >> loop(Chunk.empty(), f))
}
}
function splitInternal(
leftovers: Chunk,
input: Chunk,
f: Predicate
): Channel, unknown, E, Chunk>, unknown> {
const [chunk, remaining] = (leftovers + input).splitWhere(f)
return chunk.isEmpty || remaining.isEmpty
? loop(chunk + remaining.drop(1), f)
: Channel.write(Chunk.single(chunk)).flatMap(() =>
splitInternal(Chunk.empty(), remaining.drop(1), f)
)
}
function loop(
leftovers: Chunk,
f: Predicate
): Channel, unknown, E, Chunk>, unknown> {
return Channel.readWith(
(input: Chunk) => splitInternal(leftovers, input, f),
(err) => Channel.fail(err),
() =>
leftovers.isEmpty
? Channel.unit
: leftovers.find(f).isNone()
? Channel.write(Chunk.single(leftovers)).flatMap(() => Channel.unit)
: splitInternal(Chunk.empty(), leftovers, f).flatMap(() => Channel.unit)
)
}