vrust 0.0.1

VRust game engine
use std::collections::BTreeMap;
use std::io::{Seek, SeekFrom};
use std::mem::transmute;
use std::sync::{Arc, Weak};
use super::super::system::file::File;
use super::cell::DebugCell;

pub struct Cacher<ID, VAL: ?Sized> where ID: Ord {
    cached: BTreeMap<ID, Weak<DebugCell<VAL>>>,
}

impl<ID, VAL: ?Sized> Cacher<ID, VAL> where ID: Ord {
    pub fn new() -> Self {
        Cacher {
            cached: BTreeMap::new(),
        }
    }

    pub fn get<F>(&mut self, id: ID, new: &F) -> Arc<DebugCell<VAL>>
    where F: Fn() -> Arc<DebugCell<VAL>> {
        match self.cached.get(&id) {
            Some(res) => match res.upgrade() {
                Some(res) => {
                    return res;
                }
                None => {}
            },
            None => {}
        }
        let res = new();
        self.cached.insert(id, Arc::downgrade(&res));
        return res;
    }
}

pub struct FileCacher<VAL: ?Sized> {
    file: Arc<DebugCell<File>>,
    cached: Cacher<u64, VAL>,
    offsets: Vec<u64>,
}

impl<VAL: ?Sized> FileCacher<VAL> {
    pub fn new(file: Arc<DebugCell<File>>) -> Self {
        FileCacher {
            file: file,
            cached: Cacher::new(),
            offsets: Vec::new(),
        }
    }

    pub fn read_offsets(&mut self) {
        let mut file = self.file.borrow_mut();
        let count = file.read_count() as usize;
        self.offsets.resize(count, 0);
        for i in 0..count {
            self.offsets[i] = file.read_offset();
        }
    }

    pub fn get<'a, F>(
        &'a mut self, id: u64, new: &F
    ) -> Arc<DebugCell<VAL>>
    where F: Fn() -> Arc<DebugCell<VAL>> {
        let self_ptr: &'static usize = unsafe { transmute(&self) };
        let self2 = *self_ptr;
        self.cached.get(id, &|| {
            let self2: &'a mut FileCacher<VAL> = unsafe { transmute(self2) };
            #[cfg(cacher_debug)]
            {
                if id as usize > self2.offsets.len() {
                    logf!("Id is is out of the range.");
                }
                let offset = self2.offsets[id as usize];
                match self2.file.borrow_mut().seek(SeekFrom::Start(offset)) {
                    Ok(o) => if o < offset {
                        logf!("Seeked offset does not match!");
                    },
                    _ => {
                        logf!("Can not seek to the requested offset.");
                    }
                };
            }
            #[cfg(not(cacher_debug))] 
            {
                let _ = self2.file.borrow_mut().seek(SeekFrom::Start(self2.offsets[id as usize])).unwrap();
            }
            new()
        })
    }

    pub fn get_file(&self) -> &Arc<DebugCell<File>> {
        &self.file
    }
}