kay 0.5.1

Experimental high-performance actor system framework for Rust
use chunky;
use std::rc::Rc;
use crate::tuning::Tuning;

#[derive(Clone, Copy)]
pub struct SlotIndices {
    bin: u8,
    slot: u32,
}

impl SlotIndices {
    pub fn new(bin: usize, slot: usize) -> SlotIndices {
        SlotIndices {
            bin: bin as u8,
            slot: slot as u32,
        }
    }

    pub fn invalid() -> SlotIndices {
        SlotIndices {
            bin: u8::max_value(),
            slot: u32::max_value(),
        }
    }

    pub fn bin(&self) -> usize {
        self.bin as usize
    }

    pub fn slot(&self) -> usize {
        self.slot as usize
    }
}

impl Into<chunky::MultiArenaIndex> for SlotIndices {
    fn into(self) -> chunky::MultiArenaIndex {
        chunky::MultiArenaIndex(self.bin(), chunky::ArenaIndex(self.slot()))
    }
}

impl From<chunky::MultiArenaIndex> for SlotIndices {
    fn from(source: chunky::MultiArenaIndex) -> Self {
        Self::new(source.0, (source.1).0)
    }
}

pub struct SlotMap {
    entries: chunky::Vector<SlotIndices>,
    last_known_version: chunky::Vector<u8>,
    free_ids_with_versions: chunky::Vector<(usize, usize)>,
}

impl SlotMap {
    pub fn new(ident: &chunky::Ident, storage: Rc<dyn chunky::ChunkStorage>, tuning: &Tuning) -> Self {
        SlotMap {
            entries: chunky::Vector::new(ident.sub("entr"), tuning.instance_entry_chunk_size, Rc::clone(&storage)),
            last_known_version: chunky::Vector::new(ident.sub("vrsns"), tuning.instance_versions_chunk_size, Rc::clone(&storage)),
            free_ids_with_versions: chunky::Vector::new(ident.sub("free"), tuning.instance_free_chunk_size, storage),
        }
    }

    pub fn allocate_id(&mut self) -> (usize, usize) {
        match self.free_ids_with_versions.pop() {
            None => {
                self.entries.push(SlotIndices::invalid());
                self.last_known_version.push(0);
                (self.entries.len() - 1, 0)
            }
            Some((id, version)) => (id, version),
        }
    }

    pub fn associate(&mut self, id: usize, new_entry: SlotIndices) {
        let entry = self
            .entries
            .at_mut(id)
            .expect("Should already have entry allocated when associating");
        entry.clone_from(&new_entry);
    }

    pub fn indices_of(&self, id: usize, version: u8) -> Option<SlotIndices> {
        if let Some(last_known_version) = self.last_known_version.at(id) {
            if *last_known_version == version {
                self.indices_of_no_version_check(id)
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn indices_of_no_version_check(&self, id: usize) -> Option<SlotIndices> {
        self.entries.at(id).cloned()
    }

    pub fn free(&mut self, id: usize, version: usize) {
        *self
            .last_known_version
            .at_mut(id)
            .expect("should have last known version when freeing") = (version + 1) as u8;
        self.free_ids_with_versions.push((id, version + 1));
    }
}