/**
* Folds over the events in this collection of events using the specified
* functions.
*
* @tsplus static ParSeq.Aspects fold
* @tsplus pipeable ParSeq fold
*/
export function fold(
emptyCase: B,
singleCase: (a: A) => B,
thenCase: (l: B, r: B) => B,
bothCase: (l: B, r: B) => B
) {
return (self: ParSeq): B =>
foldLoop(
emptyCase,
singleCase,
thenCase,
bothCase,
List(self),
List.empty()
).unsafeHead!
}
function foldLoop(
emptyCase: B,
singleCase: (a: A) => B,
thenCase: (l: B, r: B) => B,
bothCase: (l: B, r: B) => B,
inp: List>,
out: List>
): List {
// eslint-disable-next-line no-constant-condition
while (1) {
if (inp.isNil()) {
return out.reduce(List.empty(), (acc, val) => {
if (val._tag === "Right") {
return acc.prepend(val.right)
} else {
if (val.left) {
let parSeqs: List = acc
const left = parSeqs.unsafeHead
parSeqs = parSeqs.unsafeTail!
const right = parSeqs.unsafeHead
parSeqs = parSeqs.unsafeTail!
return parSeqs.prepend(bothCase(left!, right!))
} else {
let parSeqs: List = acc
const left = parSeqs.unsafeHead
parSeqs = parSeqs.unsafeTail!
const right = parSeqs.unsafeHead
parSeqs = parSeqs.unsafeTail!
return parSeqs.prepend(thenCase(left!, right!))
}
}
})
} else {
const head = inp.head
const parSeqs = inp.tail
switch (head._tag) {
case "Empty": {
inp = parSeqs
out = out.prepend(Either.right(emptyCase))
break
}
case "Single": {
inp = parSeqs
out = out.prepend(Either.right(singleCase(head.a)))
break
}
case "Then": {
inp = parSeqs.prepend(head.right).prepend(head.left)
out = out.prepend(Either.left(false))
break
}
case "Both": {
inp = parSeqs.prepend(head.right).prepend(head.left)
out = out.prepend(Either.left(true))
break
}
}
}
}
throw new Error("Bug")
}