dewit 0.0.1

Define scheduling and execution of code separately from data flow
Documentation
use core::marker::PhantomData;

use crate::{
    mode::Mode,
    task::{
        Task,
        TaskOutput,
    },
};

struct Then<A, B, IO> {
    prev: A,
    next: B,
    _phantom: PhantomData<IO>,
}

impl<'src, I, IO, O, S1, S2> Task<'src, I, O> for Then<S1, S2, IO>
where
    IO: Send + 'src,
    O: Send + 'src,
    S1: Task<'src, I, IO>,
    S2: Task<'src, IO, O> + Send + 'src,
{
    go_impl!('src, I, O);

    #[inline]
    fn go<M>(self, mode: &'src M, input: I) -> TaskOutput<'src, M, O>
    where
        Self: Sized,
        M: Mode<'src> + Send + Sync,
    {
        mode.then(self.prev.go(mode, input), move |mode, output| {
            self.next.go(mode, output)
        })
    }
}

/// Combine two tasks by feeding the output of one into the next.
///
/// For ergonomics, [`Task::then`] should be preferred, but until `const` trait
/// functions are stabilized this function permits _constructing_ a [`Task`] to
/// be evaluated at compile time.
#[inline(always)]
pub const fn then<'src, I, IO, O>(
    a: impl Task<'src, I, IO>,
    b: impl Task<'src, IO, O> + Send + 'src,
) -> impl Task<'src, I, O>
where
    IO: Send + 'src,
    O: Send + 'src,
{
    Then {
        prev: a,
        next: b,
        _phantom: PhantomData,
    }
}