use std::sync::Arc;
use std::marker::PhantomData;
use std::{fmt, mem, borrow, cmp, hash};
use std::ops::Deref;
#[derive(Debug)]
pub enum SlowRMBA<'a, T: 'a + ?Sized> {
Ref(&'a T),
RefMut(&'a mut T),
Box(Box<T>),
Arc(Arc<T>),
}
impl<'a, T: 'a + ?Sized> SlowRMBA<'a, T> {
pub fn try_clone(&self) -> Option<SlowRMBA<'a, T>> {
match self {
&SlowRMBA::Ref(ref t) => Some(SlowRMBA::Ref(t)),
&SlowRMBA::Arc(ref t) => Some(SlowRMBA::Arc(t.clone())),
_ => None,
}
}
pub fn get_mut(&mut self) -> Option<&mut T> {
match self {
&mut SlowRMBA::RefMut(ref mut t) => Some(t),
&mut SlowRMBA::Box(ref mut t) => Some(t),
&mut SlowRMBA::Arc(ref mut t) => Arc::get_mut(t),
_ => None,
}
}
}
impl<'a, T: 'a + ?Sized> Deref for SlowRMBA<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
match self {
&SlowRMBA::Ref(ref t) => t,
&SlowRMBA::RefMut(ref t) => t,
&SlowRMBA::Box(ref t) => t,
&SlowRMBA::Arc(ref t) => t,
}
}
}
pub struct RMBA<'a, T: 'a + ?Sized>(*const T, PhantomData<SlowRMBA<'a, T>>);
impl<'a, T: 'a> RMBA<'a, T> {
pub fn new_box(t: T) -> RMBA<'a, T> { Box::new(t).into() }
}
unsafe impl<'a, T: 'a + ?Sized + Send> Send for RMBA<'a, T> {}
impl<'a, T: 'a + ?Sized> RMBA<'a, T> {
#[inline]
fn unpack(&self) -> (*const T, usize) {
let mut p = self.0;
let f: *mut usize = (&mut p) as *mut _ as *mut usize;
unsafe {
let g = *f & 3;
*f = *f & (!3);
(p, g)
}
}
fn make(mut p: *const T, add: usize) -> RMBA<'a, T> {
let f: *mut usize = (&mut p) as *mut _ as *mut usize;
debug_assert!(add <= 3);
unsafe {
assert!(*f & 3 == 0);
*f = *f + add;
};
RMBA(p, PhantomData)
}
unsafe fn arc(mut p: *const T) -> Arc<T> {
use std::sync::atomic::AtomicUsize;
let f: *mut usize = (&mut p) as *mut _ as *mut usize;
*f = *f - 2*mem::size_of::<AtomicUsize>();
mem::transmute(p)
}
pub fn new<A: Into<RMBA<'a, T>>>(t: A) -> RMBA<'a, T> { t.into() }
pub fn try_clone(&self) -> Option<RMBA<'a, T>> {
match self.unpack() {
(_, 0) => Some(RMBA(self.0, PhantomData)),
(p, 2) => unsafe {
let a = Self::arc(p);
let r = Some(a.clone().into());
mem::forget(a);
r
},
_ => None,
}
}
pub fn get_mut(&mut self) -> Option<&mut T> {
match self.unpack() {
(p, 1) => unsafe {
let mut b = Box::<T>::from_raw(p as *mut T);
let z: *mut T = &mut *b;
mem::forget(b);
Some(&mut *z)
},
(p, 2) => unsafe {
let mut a = Self::arc(p);
let r = mem::transmute(Arc::get_mut(&mut a));
mem::forget(a);
r
},
(p, 3) => unsafe { Some(&mut *(p as *mut T)) },
_ => None,
}
}
}
impl<'a, T: 'a + ?Sized> From<&'a T> for RMBA<'a, T> {
fn from(t: &'a T) -> RMBA<'a, T> { RMBA::make(t as *const T, 0) }
}
impl<'a, T: 'a + ?Sized> From<&'a mut T> for RMBA<'a, T> {
fn from(t: &'a mut T) -> RMBA<'a, T> { RMBA::make(t as *const T, 3) }
}
impl<'a, T: 'a + ?Sized> From<Box<T>> for RMBA<'a, T> {
fn from(t: Box<T>) -> RMBA<'a, T> { RMBA::make(Box::into_raw(t) as *const T, 1) }
}
impl<'a, T: 'a + ?Sized> From<Arc<T>> for RMBA<'a, T> {
fn from(t: Arc<T>) -> RMBA<'a, T> {
let z = RMBA::make(&*t, 2);
mem::forget(t);
z
}
}
impl<'a, T: 'a + ?Sized> fmt::Debug for RMBA<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RMBA({})", match self.unpack().1 { 0 => "&", 1 => "Box", 2 => "Arc", 3 => "&mut", _ => unreachable!() })
}
}
impl<'a, T: 'a + ?Sized> Deref for RMBA<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T { unsafe { &*self.unpack().0 }}
}
unsafe impl<'a, T: 'a + ?Sized> crate::StableDeref for RMBA<'a, T> {}
impl<'a, T: 'a + ?Sized> Drop for RMBA<'a, T> {
fn drop(&mut self) {
match self.unpack() {
(_, 0) => {},
(p, 1) => unsafe { let _ = Box::<T>::from_raw(p as *mut T); },
(p, 2) => unsafe { let _ = Self::arc(p); },
(_, 3) => {},
_ => unreachable!(),
}
}
}
impl<'a, T: 'a + ?Sized> AsRef<T> for RMBA<'a, T> {
fn as_ref(&self) -> &T {
&*self
}
}
impl<'a, T: 'a + ?Sized> borrow::Borrow<T> for RMBA<'a, T> {
fn borrow(&self) -> &T {
&*self
}
}
impl<'a, T: 'a + ?Sized + hash::Hash> hash::Hash for RMBA<'a, T> {
#[inline]
fn hash<H>(&self, state: &mut H) where H: hash::Hasher { (**self).hash(state) }
}
impl<'a, T: 'a + ?Sized + PartialEq> PartialEq for RMBA<'a, T> {
#[inline]
fn eq(&self, other: &Self) -> bool { **self == **other }
#[inline]
fn ne(&self, other: &Self) -> bool { **self != **other }
}
impl<'a, T: 'a + ?Sized + Eq> Eq for RMBA<'a, T> {}
impl<'a, T: 'a + ?Sized + PartialOrd> PartialOrd for RMBA<'a, T> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { (**self).partial_cmp(&**other) }
#[inline]
fn lt(&self, other: &Self) -> bool { **self < **other }
#[inline]
fn le(&self, other: &Self) -> bool { **self <= **other }
#[inline]
fn gt(&self, other: &Self) -> bool { **self > **other }
#[inline]
fn ge(&self, other: &Self) -> bool { **self >= **other }
}
impl<'a, T: ?Sized + Ord> Ord for RMBA<'a, T> {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering { (**self).cmp(&**other) }
}
#[test]
fn rmba_fat() {
trait Dummy { fn foo(&self) -> i32; }
impl Dummy for u8 { fn foo(&self) -> i32 { *self as i32 } }
impl Dummy for i32 { fn foo(&self) -> i32 { *self } }
let z: SlowRMBA<dyn Dummy> = SlowRMBA::Box(Box::new(9u8));
let r: RMBA<dyn Dummy> = (Box::new(9i32) as Box<dyn Dummy>).into();
let a: RMBA<dyn Dummy> = (Arc::new(17i32) as Arc<dyn Dummy>).into();
assert_eq!(r.foo(), z.foo());
assert_eq!(a.try_clone().unwrap().foo(), 17i32);
}
#[test]
fn rmba_box() {
let mut z = RMBA::new_box(78);
assert!(z.try_clone().is_none());
assert_eq!(*z, 78);
*z.get_mut().unwrap() = 73;
assert_eq!(*z, 73);
assert!(z > RMBA::new_box(72));
assert!(z < RMBA::new_box(74));
assert!(z == RMBA::new(Arc::new(73)));
assert!(z != RMBA::new_box(75));
}
#[test]
fn rmba_arc() {
let mut a = Arc::new(53);
let mut f = RMBA::new(a.clone());
{
let f2: &i32 = &f;
assert_eq!(53, *f2);
}
assert!(f.get_mut().is_none());
assert!(Arc::get_mut(&mut a).is_none());
let z = f.try_clone().unwrap();
drop(f);
assert!(Arc::get_mut(&mut a).is_none());
drop(z);
assert!(Arc::get_mut(&mut a).is_some());
}
#[test]
#[should_panic]
fn rmba_unaligned() {
let b = vec![5u8, 7u8];
let _ = RMBA::new(&b[0]);
let _ = RMBA::new(&b[1]);
}
#[test]
fn rmba_typical() {
struct Dummy {
a: Arc<i32>,
b: RMBA<'static, i32>,
}
let z = Arc::new(5i32);
let d = Dummy { a: z.clone(), b: RMBA::new(z) };
assert_eq!(&*d.b, &5i32);
assert_eq!(&*d.a, &5i32);
}
#[test]
fn rmba_sizes() {
use std::mem::size_of;
assert_eq!(size_of::<&i32>(), size_of::<RMBA<i32>>());
assert!(size_of::<RMBA<i32>>() < size_of::<SlowRMBA<i32>>());
}