crux_core 0.19.0

Cross-platform app development in Rust
Documentation
use slab::Slab;

use super::effect_id;
use crate::RequestHandle;

pub struct Storage<Out> {
    pub(crate) handles: Slab<Option<RequestHandle<Out>>>,
    pub(crate) generations: Vec<u32>,
}

impl<Out> Default for Storage<Out> {
    fn default() -> Self {
        Self {
            handles: Slab::with_capacity(256),
            generations: Vec::with_capacity(256),
        }
    }
}

impl<Out> Storage<Out> {
    pub(crate) fn insert(&mut self, handle: RequestHandle<Out>) -> effect_id::EffectId<Out> {
        let entry = self.handles.vacant_entry();
        let index = entry.key();

        if self.generations.len() == index {
            self.generations.push(0);
        }
        debug_assert!(self.generations.len() > index);

        let generation = self.generations[index];
        entry.insert(Some(handle));

        effect_id::EffectId::new(index, generation)
    }

    pub(crate) fn take(&mut self, id: effect_id::EffectId<Out>) -> Option<RequestHandle<Out>> {
        if self.generations.get(id.index()).copied()? != id.generation() {
            return None;
        }

        self.handles.get_mut(id.index())?.take()
    }

    pub(crate) fn reinsert(&mut self, id: effect_id::EffectId<Out>, handle: RequestHandle<Out>) {
        let Some(entry) = self.handles.get_mut(id.index()) else {
            return;
        };

        debug_assert_eq!(self.generations[id.index()], id.generation());
        debug_assert!(entry.is_none());

        *entry = Some(handle);
    }

    pub(crate) fn remove(&mut self, id: effect_id::EffectId<Out>) {
        if self.generations.get(id.index()).copied() != Some(id.generation()) {
            return;
        }

        if self.handles.contains(id.index()) {
            self.handles.remove(id.index());
            self.generations[id.index()] = self.generations[id.index()].wrapping_add(1);
        }
    }
}