io-engine 0.9.1

Library for block-based IO, intend to mask AIO/io_uring underneath.
Documentation
use crate::tasks::{IOCallback, IOEvent};
use crossfire::{MTx, Tx, flavor::Flavor, mpmc};

/// A trait for workers that accept IO events.
///
/// This allows using either `IOWorkers` (wrappers around channels) or direct channels
/// (`MTx`, `Tx`) or any other sink, or even process inline.
pub trait Worker<C: IOCallback>: Send + 'static {
    fn done(&self, event: Box<IOEvent<C>>);
}

/// Example callback worker implement with crossfire::mpmc, can be shared among multiple driver instances.
///
/// # Safety
///
/// It does not check and resubmit short I/O
pub struct IOWorkers<C: IOCallback>(pub(crate) MTx<mpmc::Array<Box<IOEvent<C>>>>);

impl<C: IOCallback> IOWorkers<C> {
    pub fn new(workers: usize) -> Self {
        let (tx, rx) = mpmc::bounded_blocking::<Box<IOEvent<C>>>(100000);
        for _i in 0..workers {
            let _rx = rx.clone();
            std::thread::spawn(move || {
                loop {
                    match _rx.recv() {
                        Ok(event) => event.callback_unchecked(true),
                        Err(_) => {
                            debug!("IOWorkers exit");
                            return;
                        }
                    }
                }
            });
        }
        Self(tx)
    }
}

impl<C: IOCallback> Clone for IOWorkers<C> {
    fn clone(&self) -> Self {
        Self(self.0.clone())
    }
}

impl<C: IOCallback> Worker<C> for IOWorkers<C> {
    fn done(&self, item: Box<IOEvent<C>>) {
        let _ = self.0.send(item);
    }
}

// Implement Worker for Crossfire MTx (Multi-Producer)
impl<C, F> Worker<C> for MTx<F>
where
    F: Flavor<Item = Box<IOEvent<C>>>,
    C: IOCallback,
{
    fn done(&self, item: Box<IOEvent<C>>) {
        let _ = self.send(item);
    }
}

// Implement Worker for Crossfire Tx (Single-Producer)
impl<C, F> Worker<C> for Tx<F>
where
    F: Flavor<Item = Box<IOEvent<C>>>,
    C: IOCallback,
{
    fn done(&self, item: Box<IOEvent<C>>) {
        let _ = self.send(item);
    }
}

/// Example Inline worker that executes callbacks directly without spawning threads.
/// Use this for very lightweight callback logic to avoid thread context switching overhead.
///
/// # Safety
///
/// It does not check and resubmit short I/O
pub struct Inline;

impl<C: IOCallback> Worker<C> for Inline {
    fn done(&self, event: Box<IOEvent<C>>) {
        event.callback_unchecked(true);
    }
}