froggy 0.4.4

Froggy is a prototype for the Component Graph System programming model. It aims to combine the convenience of composition-style Object-Oriented Programming with the performance close to Entity-Component Systems.
Documentation
use {Epoch, Index, StorageId};

#[derive(Copy, Clone, Debug, PartialEq, Hash)]
pub struct PointerData(u64);

#[cfg(target_pointer_width = "32")]
const INDEX_BITS: u8 = 20;
#[cfg(target_pointer_width = "32")]
const EPOCH_BITS: u8 = 8;
#[cfg(target_pointer_width = "32")]
const STORAGE_ID_BITS: u8 = 4;

#[cfg(target_pointer_width = "64")]
const INDEX_BITS: u8 = 40;
#[cfg(target_pointer_width = "64")]
const EPOCH_BITS: u8 = 16;
#[cfg(target_pointer_width = "64")]
const STORAGE_ID_BITS: u8 = 8;

const INDEX_MASK: u64 = (1 << INDEX_BITS) - 1;
const EPOCH_OFFSET: u8 = INDEX_BITS;
const EPOCH_MASK: u64 = ((1 << EPOCH_BITS) - 1) << EPOCH_OFFSET;
const STORAGE_ID_OFFSET: u8 = EPOCH_OFFSET + EPOCH_BITS;
const STORAGE_ID_MASK: u64 = ((1 << STORAGE_ID_BITS) - 1) << STORAGE_ID_OFFSET;

impl PointerData {
    #[inline]
    pub fn new(index: Index, epoch: Epoch, storage: StorageId) -> Self {
        debug_assert_eq!(index >> INDEX_BITS, 0);
        PointerData(index as u64 + ((epoch as u64) << EPOCH_OFFSET) +
            ((storage as u64) << STORAGE_ID_OFFSET))
    }

    #[inline]
    pub fn get_index(&self) -> Index {
        (self.0 & INDEX_MASK) as Index
    }

    #[inline]
    pub fn get_epoch(&self) -> Epoch {
        ((self.0 & EPOCH_MASK) >> EPOCH_OFFSET) as Epoch
    }

    #[inline]
    pub fn get_storage_id(&self) -> StorageId {
        ((self.0 & STORAGE_ID_MASK) >> STORAGE_ID_OFFSET) as StorageId
    }

    #[inline]
    pub fn with_epoch(&self, epoch: Epoch) -> PointerData {
        PointerData((self.0 & !EPOCH_MASK) + ((epoch as u64) << EPOCH_OFFSET))
    }
}

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

    #[test]
    fn sizes() {
        #[cfg(target_pointer_width = "32")]
        assert_eq!(INDEX_BITS + EPOCH_BITS + STORAGE_ID_BITS, 32);
        #[cfg(target_pointer_width = "64")]
        assert_eq!(INDEX_BITS + EPOCH_BITS + STORAGE_ID_BITS, 64);
        assert!(size_of::<Index>() * 8 >= INDEX_BITS as usize);
        assert!(size_of::<Epoch>() * 8 >= EPOCH_BITS as usize);
        assert!(size_of::<StorageId>() * 8 >= STORAGE_ID_BITS as usize);
    }

    #[test]
    fn new() {
        let pd = PointerData::new(1, 2, 3);
        assert_eq!(pd.get_index(), 1);
        assert_eq!(pd.get_epoch(), 2);
        assert_eq!(pd.get_storage_id(), 3);
        assert_eq!(pd.with_epoch(5).get_epoch(), 5);
    }
}