use std::cell::UnsafeCell;
use std::fmt;
use std::mem;
use std::ops;
use std::ptr;
pub struct MoveCell<T>(UnsafeCell<T>);
impl<T> MoveCell<T> {
#[inline]
pub fn new(value: T) -> MoveCell<T> {
MoveCell(UnsafeCell::new(value))
}
#[inline]
pub fn into_inner(self) -> T {
unsafe { self.0.into_inner() }
}
#[inline]
pub fn replace(&self, new_value: T) -> T {
unsafe {
mem::replace(&mut *self.0.get(), new_value)
}
}
#[inline]
pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell<T> {
&self.0
}
}
impl<T: Default> Default for MoveCell<T> {
#[inline]
fn default() -> MoveCell<T> {
MoveCell::new(T::default())
}
}
impl<T: Default> MoveCell<T> {
#[inline]
pub fn take(&self) -> T {
self.replace(T::default())
}
#[inline]
pub fn borrow(&self) -> Borrow<T> {
Borrow {
_cell: self,
_value: self.take()
}
}
}
impl<T: Default + Clone> Clone for MoveCell<T> {
#[inline]
fn clone(&self) -> MoveCell<T> {
MoveCell::new(self.borrow().clone())
}
}
impl<T: Default + fmt::Debug> fmt::Debug for MoveCell<T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "MoveCell({:?})", *self.borrow())
}
}
impl<T: Default + Eq> Eq for MoveCell<T> {}
impl<T: Default + PartialEq> PartialEq for MoveCell<T> {
#[inline]
fn eq(&self, other: &MoveCell<T>) -> bool {
*self.borrow() == *other.borrow()
}
#[inline]
fn ne(&self, other: &MoveCell<T>) -> bool {
*self.borrow() != *other.borrow()
}
}
pub struct Borrow<'a, T: 'a> {
_cell: &'a MoveCell<T>,
_value: T,
}
impl<'a, T> Borrow<'a, T> {
pub fn into_inner(self) -> T {
let value = unsafe { ptr::read(&self._value) };
mem::forget(self);
value
}
}
impl<'a, T> Drop for Borrow<'a, T> {
fn drop(&mut self) {
mem::swap(&mut self._value, unsafe { &mut *self._cell.as_unsafe_cell().get() })
}
}
impl<'a, T> ops::Deref for Borrow<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T { &self._value }
}
impl<'a, T> ops::DerefMut for Borrow<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T { &mut self._value }
}
impl<'a, T: fmt::Debug> fmt::Debug for Borrow<'a, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "movecell::Borrow({:?})", self._value)
}
}
#[test]
fn it_works() {
let x = MoveCell::new("first".to_owned());
assert_eq!(x.replace("second".to_owned()), "first");
assert_eq!(x.replace("third".to_owned()), "second");
assert_eq!(x.into_inner(), "third");
let x = MoveCell::new(Some("fourth".to_owned()));
assert_eq!(x.take(), Some("fourth".to_owned()));
assert_eq!(x.take(), None);
assert_eq!(x.replace(Some("fifth".to_owned())), None);
assert_eq!(&*x.borrow(), &Some("fifth".to_owned()));
assert_eq!(x.borrow().as_ref().map(|s| s.len()), Some(5));
assert_eq!(x.borrow().clone(), Some("fifth".to_owned()));
assert_eq!(x.borrow().is_some(), true);
assert_eq!(x.borrow().is_none(), false);
assert_eq!(x.clone(), x);
assert_eq!(format!("{:?}", x), "MoveCell(Some(\"fifth\"))");
assert_eq!(format!("{:?}", x.borrow()), "movecell::Borrow(Some(\"fifth\"))");
assert_eq!(x.take(), Some("fifth".to_owned()));
assert_eq!(x.borrow().is_some(), false);
assert_eq!(x.borrow().is_none(), true);
assert_eq!(&*x.borrow(), &None);
assert_eq!(x.clone(), x);
assert_eq!(format!("{:?}", x), "MoveCell(None)");
}