Documentation
//! A two-level LRU cache.
//!
//! Two keys are used in the cache, one to access another layer of LRU caches,
//! and the second to store a payload in that bottom-layered cache.
use register::Register;
pub use self::cacheable::Cacheable;

mod cacheable;
#[cfg(test)]
mod test;
#[cfg(test)]
mod bench;

/// The two-level LRU cache
#[allow(dead_code)]
pub struct Cache<C: Cacheable> {
    register: Box<Register<C::UpperKey, *mut Register<C::LowerKey, C::Payload>>>,
    registers: Box<[Register<C::LowerKey, C::Payload>]>
}

impl<C: Cacheable> Cache<C> {
    /// Create a new LRU cache of caches
    ///
    /// `cache_size` specifies the number of caches in the second layer.
    /// `register_size` specifies the number of entries in each second-layer cache.
    pub fn new(cache_size: usize, register_size: usize) -> Cache<C> {
        let mut registers = Vec::with_capacity(cache_size);
        let mut register = Register::new(cache_size);
        for _ in 0..cache_size {
            registers.push(Register::<C::LowerKey, C::Payload>::new(register_size));
        }
        let mut registers_box = registers.into_boxed_slice();
        for i in 0..cache_size {
            register.entries[i].payload = &mut registers_box[i] as *mut Register<C::LowerKey, C::Payload>;
        }

        Cache{
            register: Box::new(register),
            registers: registers_box
        }
    }

    /// Set a payload beneath two keys
    ///
    /// The `cache_key` is more general, and can have multiple `register_keys` stored under it.
    #[inline]
    pub fn set(&mut self, upper_key: C::UpperKey, lower_key: C::LowerKey, payload: C::Payload) -> bool {
        match self.register.get(upper_key) {
            Some(pcache) => {
                let mut cache: &mut Register<C::LowerKey, C::Payload> = unsafe{ &mut **pcache };
                return cache.set(lower_key, Some(payload))
            },
            None => ()
        }

        self.register.set(upper_key, None);
        let mut cache: &mut Register<C::LowerKey, C::Payload> = unsafe{ &mut **self.register.get(upper_key).unwrap() };
        cache.reset();
        cache.set(lower_key, Some(payload))
    }

    /// Check if any payloads are set under a given `cache_key`, and return the number of payloads set
    #[inline]
    pub fn has(&mut self, upper_key: C::UpperKey) -> Option<usize> {
        self.register.get(upper_key).map(|pcache| unsafe{ &mut **pcache }.cur_size )
    }

    /// Get a payload set (if any) under a given set of keys
    #[inline]
    pub fn get(&mut self, upper_key: C::UpperKey, lower_key: C::LowerKey) -> Option<&C::Payload> {
        match self.register.get(upper_key) {
            Some(pcache) => {
                let cache: &mut Register<C::LowerKey, C::Payload> = unsafe{ &mut **pcache };
                cache.get(lower_key)
            },
            None => None
        }
    }
}

#[cfg(test)]
struct Types;

#[cfg(test)]
impl Cacheable for Types {
    type UpperKey = u8;
    type LowerKey = u8;
    type Payload = bool;
}

#[test]
fn initialize_registers() {
    let mut cache = Cache::<Types>::new(10, 10);
    let entries = cache.register.entries;
    let mut iter = entries.iter().enumerate();

    assert!(entries.len() == 10);
    loop {
        match iter.next() {
            Some((i, entry)) => {
                assert!(entry.payload == &mut cache.registers[i] as *mut Register<u8, bool>);
            },
            None => { break; }
        }
    }
}