1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
use super::{Data, ProcData};
use crate::{fib, sv::Switch};
use core::{marker::PhantomData, mem::forget};

/// A zero-sized token that provides [`proc_yield`](Yielder::proc_yield) method
/// to yield from [`FiberProc`](crate::fib::FiberProc).
pub struct Yielder<Sv, I, Y, R>
where
    Sv: Switch<ProcData<I, Y, R>>,
    I: Send + 'static,
    Y: Send + 'static,
    R: Send + 'static,
{
    _sv: PhantomData<*const Sv>,
    _input: PhantomData<*const I>,
    _yield: PhantomData<*const Y>,
    _return: PhantomData<*const R>,
}

#[allow(clippy::unused_self)]
impl<Sv, I, Y, R> Yielder<Sv, I, Y, R>
where
    Sv: Switch<ProcData<I, Y, R>>,
    I: Send + 'static,
    Y: Send + 'static,
    R: Send + 'static,
{
    /// Creates a new yielder token.
    ///
    /// # Safety
    ///
    /// The token must be created only in a closure provided to a
    /// [`FiberProc`](crate::fib::FiberProc). The type parameters for the
    /// [`Yielder`] must be equal to the type parameters for the
    /// [`FiberProc`](crate::fib::FiberProc).
    #[inline]
    pub unsafe fn new() -> Self {
        Self {
            _sv: PhantomData,
            _input: PhantomData,
            _yield: PhantomData,
            _return: PhantomData,
        }
    }

    /// Yields from the [`FiberProc`](crate::fib::FiberProc).
    ///
    /// This method blocks, the stack is saved, and the fiber is suspended.
    #[inline]
    pub fn proc_yield(self, output: Y) -> I {
        unsafe {
            let mut data = Data::from_output(fib::Yielded(output));
            let mut data_ptr = &mut data as *mut _;
            Sv::switch_back(&mut data_ptr);
            forget(data);
            data_ptr.read().into_input()
        }
    }
}

impl<Sv, I, Y, R> Clone for Yielder<Sv, I, Y, R>
where
    Sv: Switch<ProcData<I, Y, R>>,
    I: Send + 'static,
    Y: Send + 'static,
    R: Send + 'static,
{
    fn clone(&self) -> Self {
        unsafe { Self::new() }
    }
}

impl<Sv, I, Y, R> Copy for Yielder<Sv, I, Y, R>
where
    Sv: Switch<ProcData<I, Y, R>>,
    I: Send + 'static,
    Y: Send + 'static,
    R: Send + 'static,
{
}

mod compile_tests {
    //! ```compile_fail
    //! use drone_cortex_m::{fib::Yielder, sv, sv::SwitchBackService, sv::SwitchContextService};
    //! sv!(pub struct Sv; static SERVICES; SwitchContextService; SwitchBackService;);
    //! fn assert_send<T: Send>() {}
    //! fn main() {
    //!     assert_send::<Yielder<Sv, (), (), ()>>();
    //! }
    //! ```
    //!
    //! ```compile_fail
    //! use drone_cortex_m::{fib::Yielder, sv, sv::SwitchBackService, sv::SwitchContextService};
    //! sv!(pub struct Sv; static SERVICES; SwitchContextService; SwitchBackService;);
    //! fn assert_sync<T: Sync>() {}
    //! fn main() {
    //!     assert_sync::<Yielder<Sv, (), (), ()>>();
    //! }
    //! ```
}