hirun 0.1.13

A concurrent framework for asynchronous programming based on event-driven, non-blocking I/O mechanism
Documentation
use crate::event::{SchedImpl, Scheduler};
use crate::thread::{self, JoinHandle, Semaphore};
use crate::Result;
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use hipool::{Allocator, Boxed, Pool};

pub trait Runnable {
    type Context;
    fn active(&mut self, ctx: &mut Self::Context) -> Result<()>;
}

impl<'a, T: Runnable<Context = ThreadContext<'a, A>> + Send, A: Allocator> Runnable
    for Boxed<'a, T, A>
{
    type Context = T::Context;
    fn active(&mut self, ctx: &mut Self::Context) -> Result<()> {
        Runnable::active(&mut **self, ctx)
    }
}

#[repr(C)]
pub struct ThreadContext<'a, A: Allocator> {
    sched: Boxed<'a, Scheduler, A>,
}

impl<'a, A: Allocator> ThreadContext<'a, A> {
    pub fn sched(&mut self) -> &mut Scheduler {
        self.sched.as_mut()
    }
    pub fn stop(&mut self) {
        self.sched.stop();
    }
}

#[repr(C)]
pub(crate) struct Thread<'a, T, A: Allocator> {
    ctx: ThreadContext<'a, A>,
    body: T,
}

unsafe impl<T: Send, A: Allocator + Pool> Send for Thread<'_, T, A> {}

impl<T: Runnable<Context = ThreadContext<'static, A>> + Send + 'static, A: Allocator + Pool>
    Thread<'static, T, A>
{
    pub(crate) fn new_in(pool: &'static A, body: T) -> Result<ThreadProxy> {
        let sched = SchedImpl::new_in(pool)?;
        let mut this = Boxed::new_in(
            pool,
            Self {
                ctx: ThreadContext { sched },
                body,
            },
        )?;
        let sem = Semaphore::new().unwrap();
        let sem_ref = unsafe { &*(&sem as *const Semaphore) };
        let handle = thread::spawn(move || match this.active() {
            Ok(_) => {
                sem_ref.post();
                this.ctx.sched.run();
            }
            Err(err) => panic!("Thread Body active failed, errno = {err}"),
        });
        sem_ref.wait();
        Ok(ThreadProxy {
            handle: ManuallyDrop::new(handle),
            mark: PhantomData,
        })
    }
}

impl<'a, T: Runnable<Context = ThreadContext<'a, A>> + Send, A: Allocator> Thread<'a, T, A> {
    fn active(&mut self) -> Result<()> {
        self.body.active(&mut self.ctx)
    }
}

pub struct ThreadProxy {
    handle: ManuallyDrop<JoinHandle<()>>,
    mark: PhantomData<*const ()>,
}

unsafe impl Send for ThreadProxy {}

impl ThreadProxy {
    pub(crate) fn join(&mut self) {
        let _ = unsafe { ManuallyDrop::take(&mut self.handle) }.join();
    }
}