ic-timers 0.26.1

Observable and recovery-aware timers for Internet Computer canisters
Documentation
//! Bounded callback environments; a slot is reusable only after ownership returns.
#![forbid(unsafe_code)]

pub(super) struct Slots<T, const LIMIT: usize>(Vec<Option<T>>);

impl<T, const LIMIT: usize> Slots<T, LIMIT> {
    pub(super) const fn new() -> Self {
        Self(Vec::new())
    }

    pub(super) fn insert(&mut self, value: T) -> Result<usize, T> {
        let index = self
            .0
            .iter()
            .position(Option::is_none)
            .unwrap_or(self.0.len());
        if index == LIMIT {
            return Err(value);
        }
        if index == self.0.len() {
            self.0.push(Some(value));
        } else {
            self.0[index] = Some(value);
        }
        Ok(index)
    }

    pub(super) fn take(&mut self, index: usize) -> Option<T> {
        self.0.get_mut(index).and_then(Option::take)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn saturation_preserves_owners_and_only_returned_slots_are_reused() {
        let mut slots = Slots::<_, 128>::new();
        for value in 0..128 {
            assert_eq!(slots.insert(value), Ok(value));
        }
        assert_eq!(slots.insert(999), Err(999));
        assert_eq!(slots.take(usize::MAX), None);
        assert_eq!(slots.take(17), Some(17));
        assert_eq!(slots.take(17), None);
        assert_eq!(slots.insert(999), Ok(17));
        for index in 0..128 {
            assert_eq!(
                slots.take(index),
                Some(if index == 17 { 999 } else { index })
            );
        }
        assert_eq!(slots.insert(1000), Ok(0));
        assert_eq!(slots.0.len(), 128);
    }
}