use crate::{InitSans, Sans, step::Step};
pub struct AndThen<S1, S2, F> {
state: AndThenState<S1, S2, F>,
}
impl<I, O, L, R, F> Sans<I, O> for AndThen<L, R::Next, F>
where
L: Sans<I, O>,
R: InitSans<I, O>,
R::Next: Sans<I, O>,
F: FnOnce(L::Return) -> R,
{
type Return = <R::Next as Sans<I, O>>::Return;
fn next(&mut self, input: I) -> Step<O, Self::Return> {
self.state.next(input)
}
}
enum AndThenState<S1, S2, F> {
OnFirst(S1, Option<F>),
OnSecond(S2),
}
impl<I, O, L, R, F> Sans<I, O> for AndThenState<L, R::Next, F>
where
L: Sans<I, O>,
R: InitSans<I, O>,
R::Next: Sans<I, O>,
F: FnOnce(L::Return) -> R,
{
type Return = <R::Next as Sans<I, O>>::Return;
fn next(&mut self, input: I) -> Step<O, Self::Return> {
match self {
AndThenState::OnFirst(l, f) => match l.next(input) {
Step::Yielded(o) => Step::Yielded(o),
Step::Complete(a) => {
let r = f.take().expect("AndThen::can only be used once")(a);
match r.init() {
Step::Yielded((o, next_r)) => {
*self = AndThenState::OnSecond(next_r);
Step::Yielded(o)
}
Step::Complete(d) => Step::Complete(d),
}
}
},
AndThenState::OnSecond(r) => r.next(input),
}
}
}
pub fn and_then<I, O, L, R, F>(l: L, f: F) -> AndThen<L, R::Next, F>
where
L: Sans<I, O>,
R: InitSans<I, O>,
R::Next: Sans<I, O>,
F: FnOnce(L::Return) -> R,
{
AndThen {
state: AndThenState::OnFirst(l, Some(f)),
}
}
pub fn chain<I, O, L, R>(l: L, r: R) -> Chain<L, R>
where
L: Sans<I, O, Return = I>,
R: Sans<I, O>,
{
Chain(Some(l), r)
}
pub fn init_chain<I, O, L, R>(l: L, r: R) -> Chain<L, R>
where
L: InitSans<I, O>,
R: Sans<I, O>,
L::Next: Sans<I, O, Return = I>,
{
Chain(Some(l), r)
}
pub struct Chain<S1, S2>(Option<S1>, S2);
impl<I, O, L, R> Sans<I, O> for Chain<L, R>
where
L: Sans<I, O, Return = I>,
R: Sans<I, O>,
{
type Return = R::Return;
fn next(&mut self, input: I) -> Step<O, Self::Return> {
match self.0 {
Some(ref mut l) => match l.next(input) {
Step::Yielded(o) => Step::Yielded(o),
Step::Complete(a) => {
self.0 = None; self.1.next(a)
}
},
None => self.1.next(input),
}
}
}
impl<I, O, L, R> InitSans<I, O> for Chain<L, R>
where
L: InitSans<I, O>,
R: Sans<I, O>,
L::Next: Sans<I, O, Return = I>,
{
type Next = either::Either<Chain<L::Next, R>, R>;
fn init(mut self) -> Step<(O, Self::Next), R::Return> {
match self.0.take().expect("Chain left side must be Some").init() {
Step::Yielded((o, next)) => {
Step::Yielded((o, either::Either::Left(Chain(Some(next), self.1))))
}
Step::Complete(d) => match self.1.next(d) {
Step::Yielded(o) => Step::Yielded((o, either::Either::Right(self.1))),
Step::Complete(r) => Step::Complete(r),
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::build::{once, repeat};
#[test]
fn test_chain_switches_to_second_coroutine_after_first_done() {
let mut coro = chain(once(|val: u32| val + 1), repeat(|val: u32| val * 2));
assert_eq!(coro.next(3).unwrap_yielded(), 4);
assert_eq!(coro.next(4).unwrap_yielded(), 8);
assert_eq!(coro.next(5).unwrap_yielded(), 10);
}
#[test]
fn test_chain_propagates_done_from_second_coroutine() {
let mut coro = chain(once(|val: u32| val + 1), once(|val: u32| val * 2));
assert_eq!(coro.next(2).unwrap_yielded(), 3);
assert_eq!(coro.next(3).unwrap_yielded(), 6);
assert_eq!(coro.next(4).unwrap_complete(), 4);
}
#[test]
fn test_and_then_basic() {
let mut coro = and_then(
once(|x: i32| x * 2), |return_val| (return_val * 10, repeat(move |y: i32| y + return_val)),
);
assert_eq!(coro.next(5).unwrap_yielded(), 10);
assert_eq!(coro.next(7).unwrap_yielded(), 70);
assert_eq!(coro.next(3).unwrap_yielded(), 10);
assert_eq!(coro.next(5).unwrap_yielded(), 12);
}
#[test]
fn test_and_then_first_coro_yields_multiple() {
use crate::build::from_fn;
let mut count = 0;
let first = from_fn(move |x: i32| {
count += 1;
if count <= 2 {
Step::Yielded(x * count)
} else {
Step::Complete(count)
}
});
let mut coro = and_then(first, |final_count| {
(final_count * 100, once(move |x: i32| x + final_count))
});
assert_eq!(coro.next(5).unwrap_yielded(), 5); assert_eq!(coro.next(5).unwrap_yielded(), 10); assert_eq!(coro.next(0).unwrap_yielded(), 300); assert_eq!(coro.next(10).unwrap_yielded(), 13); assert_eq!(coro.next(20).unwrap_complete(), 20);
}
#[test]
fn test_and_then_with_init_sans() {
let mut coro = and_then(once(|x: i32| x + 1), |result| {
(result * 10, repeat(move |y: i32| y + result))
});
assert_eq!(coro.next(5).unwrap_yielded(), 6);
assert_eq!(coro.next(8).unwrap_yielded(), 80);
assert_eq!(coro.next(3).unwrap_yielded(), 11);
}
#[test]
fn test_and_then_completes_immediately() {
let mut coro = and_then(once(|x: i32| x * 2), |val| {
(val + 100, once(move |x: i32| x + val))
});
assert_eq!(coro.next(5).unwrap_yielded(), 10);
assert_eq!(coro.next(12).unwrap_yielded(), 112);
assert_eq!(coro.next(20).unwrap_yielded(), 32);
assert_eq!(coro.next(7).unwrap_complete(), 7);
}
}