vrust 0.0.1

VRust game engine
#[cfg(cell_debug)]
use std::sync::Mutex;
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};

#[cfg(cell_debug)]
pub struct DebugCell<T: ?Sized> {
    control: Mutex<(u64, bool)>,
    data: UnsafeCell<T>,
}

#[cfg(not(cell_debug))]
#[repr(C)]
pub struct DebugCell<T: ?Sized> {
    data: UnsafeCell<T>,
}

impl<T> DebugCell<T> {
    #[cfg(cell_debug)]
    pub fn new(data: T) -> Self {
        DebugCell {
            control: Mutex::new((0, false)),
            data: UnsafeCell::new(data),
        }
    }

    #[cfg(not(cell_debug))]
    pub fn new(data: T) -> Self {
        DebugCell {
            data: UnsafeCell::new(data),
        }
    }

}

#[cfg(cell_debug)]
pub struct DebugCellRefMut<'a, T: ?Sized + 'a> {
    cell: &'a DebugCell<T>,
}

#[cfg(cell_debug)]
impl<'a, T: ?Sized + 'a> DebugCellRefMut<'a, T> {
    fn new(cell: &'a DebugCell<T>) -> Self {
        DebugCellRefMut {
            cell: cell,
        }
    }
}

#[cfg(cell_debug)]
impl<'a, T: ?Sized> Deref for DebugCellRefMut<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.cell.data.get() }
    }
}

#[cfg(cell_debug)]
impl<'a, T: ?Sized> DerefMut for DebugCellRefMut<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.cell.data.get() }
    }
}

#[cfg(cell_debug)]
impl<'a, T: ?Sized> Drop for DebugCellRefMut<'a, T> {
    fn drop(&mut self) {
        self.cell.clear_lock();
    }
}

#[cfg(cell_debug)]
pub struct DebugCellRef<'a, T: ?Sized + 'a> {
    cell: &'a DebugCell<T>,
}

#[cfg(cell_debug)]
impl<'a, T: ?Sized + 'a> DebugCellRef<'a, T> {
    fn new(cell: &'a DebugCell<T>) -> Self {
        DebugCellRef {
            cell: cell,
        }
    }
}

#[cfg(cell_debug)]
impl<'a, T: ?Sized> Deref for DebugCellRef<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.cell.data.get() }
    }
}

#[cfg(cell_debug)]
impl<'a, T: ?Sized> Drop for DebugCellRef<'a, T> {
    fn drop(&mut self) {
        self.cell.read_unlock();
    }
}

#[cfg(not(cell_debug))]
pub type DebugCellRef<'a, T: ?Sized + 'a> = &'a T;
#[cfg(not(cell_debug))]
pub type DebugCellRefMut<'a, T: ?Sized + 'a> = &'a mut T;

impl<T> DebugCell<T> where T: ?Sized {
    #[cfg(cell_debug)]
    pub fn borrow(&self) -> DebugCellRef<T> {
        let mut locked = self.control.lock().unwrap();
        if locked.1 {
            logf!("Violation of shared mutable content.");
        }
        locked.0 += 1;
        DebugCellRef::new(self)
    }

    #[cfg(not(cell_debug))]
    pub fn borrow(&self) -> DebugCellRef<T> {
        unsafe { &*self.data.get() }
    }

    #[cfg(cell_debug)]
    pub fn borrow_mut(&self) -> DebugCellRefMut<T> {
        let mut locked = self.control.lock().unwrap();
        if locked.1 || locked.0 != 0 {
            logf!("Violation of shared mutable content.");
        }
        locked.1 = true;
        DebugCellRefMut::new(self)
    }

    #[cfg(not(cell_debug))]
    pub fn borrow_mut(&self) -> DebugCellRefMut<T> {
        unsafe { &mut *self.data.get() }
    }

    pub unsafe fn untraced_mut_ref(&self) -> &mut T {
        &mut *self.data.get()
    }

    #[cfg(cell_debug)]
    fn clear_lock(&self) {
        let mut locked = self.control.lock().unwrap();
        locked.1 = false;
    }

    #[cfg(cell_debug)]
    fn read_unlock(&self) {
        let mut locked = self.control.lock().unwrap();
        locked.0 -= 1;
    }
}

unsafe impl<T: ?Sized + Send + Sync> Send for DebugCell<T> {}

unsafe impl<T: ?Sized + Send + Sync> Sync for DebugCell<T> {}