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 Blocking<I, T, F> {
    f: F,
    _phantom: PhantomData<(I, T)>,
}

impl<'src, I, O, F> Task<'src, I, O> for Blocking<I, O, F>
where
    I: Send + 'src,
    O: Send + 'src,
    F: FnOnce(I) -> O + 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_blocking(move || (self.f)(input))
    }
}

/// Treat the wrapped closure as performing work which will block, for example
/// on an OS call, for which a [`Mode`] can implement scheduling behavior.
#[inline(always)]
pub const fn blocking<'src, I, O>(f: impl FnOnce(I) -> O + Send + 'src) -> impl Task<'src, I, O>
where
    I: Send + 'src,
    O: Send + 'src,
{
    Blocking {
        f,
        _phantom: PhantomData,
    }
}