trale 0.3.0

Trale is a minimalistic Rust async executor using io_uring for efficient, correct task execution.
Documentation
use ringbuffer::{ConstGenericRingBuffer, RingBuffer};
use slab::Slab;

pub(super) enum ResultState {
    Pending,
    Set(i32),
    Dropped,
}

pub(crate) struct OneshotStore(Slab<ResultState>);

impl OneshotStore {
    pub fn new() -> Self {
        Self(Slab::new())
    }

    #[cfg(test)]
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn set_result(&mut self, result: i32, idx: usize) {
        let r_entry = self.0.get_mut(idx).unwrap();

        if matches!(r_entry, ResultState::Dropped) {
            self.0.remove(idx);
        } else {
            *r_entry = ResultState::Set(result);
        }
    }

    pub fn get_result(&mut self, idx: usize) -> Option<i32> {
        let res = match self.0.get(idx).unwrap() {
            ResultState::Pending => None,
            ResultState::Set(result) => {
                let ret = Some(*result);
                self.0.remove(idx);
                ret
            }
            ResultState::Dropped => panic!("Should not be able to get a dropped result"),
        };

        res
    }

    pub fn drop_result(&mut self, idx: usize) {
        let r_entry = self.0.get_mut(idx).unwrap();

        if matches!(r_entry, ResultState::Set(_)) {
            self.0.remove(idx);
        } else {
            *r_entry = ResultState::Dropped;
        }
    }

    pub fn create_slot(&mut self) -> usize {
        self.0.insert(ResultState::Pending)
    }
}

struct MultishotResultState {
    results: ConstGenericRingBuffer<i32, 1024>,
    dropped: bool,
    finished: bool,
}

pub enum MultishotResult {
    Value(i32),
    Pending,
    Finished,
}

pub(crate) struct MultishotStore(Slab<MultishotResultState>);

impl MultishotStore {
    fn new() -> Self {
        Self(Slab::new())
    }

    #[cfg(test)]
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn push_result(&mut self, result: i32, idx: usize) {
        self.0.get_mut(idx).unwrap().results.push(result);
    }

    pub fn pop_result(&mut self, idx: usize) -> MultishotResult {
        let result = self.0.get_mut(idx).unwrap();

        match result.results.dequeue() {
            Some(v) => MultishotResult::Value(v),
            None => {
                if result.finished {
                    MultishotResult::Finished
                } else {
                    MultishotResult::Pending
                }
            }
        }
    }

    pub fn drop_result(&mut self, idx: usize) {
        if self.0.get_mut(idx).unwrap().finished {
            self.0.remove(idx);
        } else {
            self.0.get_mut(idx).unwrap().dropped = true;
        }
    }

    pub fn create_slot(&mut self) -> usize {
        self.0.insert(MultishotResultState {
            results: ConstGenericRingBuffer::new(),
            dropped: false,
            finished: false,
        })
    }

    pub fn set_finished(&mut self, idx: usize) {
        if self.0.get(idx).unwrap().dropped {
            self.0.remove(idx);
        } else {
            self.0.get_mut(idx).unwrap().finished = true;
        }
    }
}

pub struct RingResults {
    oneshot: OneshotStore,
    multishot: MultishotStore,
}

impl RingResults {
    pub fn new() -> Self {
        Self {
            oneshot: OneshotStore::new(),
            multishot: MultishotStore::new(),
        }
    }

    pub fn get_oneshot(&mut self) -> &mut OneshotStore {
        &mut self.oneshot
    }

    pub fn get_multishot(&mut self) -> &mut MultishotStore {
        &mut self.multishot
    }

    #[cfg(test)]
    pub fn is_empty(&self) -> bool {
        self.oneshot.is_empty() && self.multishot.is_empty()
    }
}