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,
    },
};

#[repr(transparent)]
struct Io<I, Fut, F> {
    f: F,
    _phantom: PhantomData<(I, Fut)>,
}

impl<'src, I, O, Fut, F> Task<'src, I, O> for Io<I, Fut, F>
where
    I: Send + 'src,
    O: Send + 'src,
    Fut: Future<Output = O> + Send + 'src,
    F: FnOnce(I) -> Fut + Send + 'src,
{
    go_impl!('src, I, O);

    #[inline]
    fn go<M>(self, mode: &M, input: I) -> TaskOutput<'src, M, O>
    where
        Self: Sized,
        M: Mode<'src>,
    {
        mode.spawn_io(move || (self.f)(input))
    }
}

/// Treat the wrapped closure as performing IO-bound work, for which a [`Mode`]
/// can implement scheduling behavior.
///
/// This requires a function returning a future because other IO-bound work is
/// likely better represented by [`blocking`](crate::combinators::blocking).
#[inline(always)]
pub const fn io<'src, I, O, Fut>(f: impl FnOnce(I) -> Fut + Send + 'src) -> impl Task<'src, I, O>
where
    I: Send + 'src,
    O: Send + 'src,
    Fut: Future<Output = O> + Send + 'src,
{
    Io {
        f,
        _phantom: PhantomData,
    }
}