use std::borrow::Borrow;
use std::cell::Cell;
use std::cmp::Ordering;
use std::ffi::{CStr, CString, OsStr, OsString};
use std::fmt::{Debug, Display, Formatter, Pointer, Result as FmtResult};
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::panic::{RefUnwindSafe, UnwindSafe};
use std::path::{Path, PathBuf};
use std::ptr::{self, NonNull};
use std::sync::{Arc, Weak as WeakArc};
use weak::Weak;
pub struct Drc<T>
where
T: ?Sized,
{
pub(crate) ptr: NonNull<DrcInner<T>>,
pub(crate) phantom: PhantomData<T>,
}
impl<T> Drc<T> {
pub fn new(value: T) -> Drc<T> {
Drc::from_arc(Arc::new(value))
}
}
impl<T> Drc<T>
where
T: ?Sized,
{
pub fn detach(this: &Drc<T>) -> Arc<T> {
Arc::clone(this.arc())
}
pub fn separate(this: &Drc<T>) -> Drc<T> {
Drc::from_arc(Drc::detach(this))
}
}
impl<T> Drc<T> {
pub fn try_unwrap(this: Drc<T>) -> Result<T, Drc<T>> {
if Drc::strong_count(&this, true) == 1 {
match Arc::try_unwrap(unsafe { this.take_arc() }) {
Ok(value) => {
this.strong().set(0);
let weak = this.weak().get();
if weak == 1 {
unsafe {
Box::from_raw(this.ptr.as_ptr());
}
} else {
this.weak().set(weak - 1);
}
mem::forget(this);
Ok(value)
},
Err(arc) => {
unsafe { this.set_arc(arc) };
Err(this)
},
}
} else {
Err(this)
}
}
}
impl<T> Drc<T>
where
T: ?Sized,
{
pub fn downgrade(this: &Drc<T>) -> Weak<T> {
unsafe {
let storage = this.ptr.as_ptr();
(*storage).weak.set((*storage).weak.get() + 1);
if (*storage).weak_ref.is_none() {
(*storage).weak_ref = Some(Arc::downgrade(this.arc()));
}
}
Weak { ptr: this.ptr }
}
pub fn weak_count(this: &Drc<T>, local: bool) -> usize {
if local {
this.weak().get() - 1
} else {
Arc::weak_count(this.arc())
}
}
pub fn strong_count(this: &Drc<T>, local: bool) -> usize {
if local {
this.strong().get()
} else {
Arc::strong_count(this.arc())
}
}
pub fn get_mut(this: &mut Drc<T>) -> Option<&mut T> {
if Drc::is_unique(this) {
Arc::get_mut(unsafe { this.arc_mut() })
} else {
None
}
}
pub fn ptr_eq(this: &Drc<T>, other: &Drc<T>) -> bool {
Arc::ptr_eq(this.arc(), other.arc())
}
pub fn arc_ptr_eq(this: &Drc<T>, other: &Arc<T>) -> bool {
Arc::ptr_eq(this.arc(), other)
}
pub fn linked(this: &Drc<T>, other: &Drc<T>) -> bool {
this.ptr.as_ptr() == other.ptr.as_ptr()
}
}
impl<T> Drc<T>
where
T: Clone,
{
pub fn make_mut(this: &mut Drc<T>) -> &mut T {
if Drc::strong_count(this, true) != 1 {
*this = Drc::new((**this).clone());
Arc::make_mut(unsafe { this.arc_mut() })
} else {
if Drc::weak_count(this, true) != 0 {
let arc = unsafe { this.take_arc() };
this.strong().set(0);
this.weak().set(this.weak().get() - 1);
let mut swap = Drc::from_arc(arc);
mem::swap(this, &mut swap);
mem::forget(swap);
}
Arc::make_mut(unsafe { this.arc_mut() })
}
}
}
impl<T> Drc<T>
where
T: ?Sized,
{
fn is_unique(this: &Drc<T>) -> bool {
Drc::weak_count(this, true) == 0 && Drc::strong_count(this, true) == 1
}
fn from_arc(arc: Arc<T>) -> Drc<T> {
unsafe {
Drc {
ptr: NonNull::new_unchecked(Box::into_raw(Box::new(DrcInner {
strong: Cell::new(1),
weak: Cell::new(1),
strong_ref: Some(arc),
weak_ref: None,
}))),
phantom: PhantomData,
}
}
}
fn weak(&self) -> &Cell<usize> {
unsafe { &self.ptr.as_ref().weak }
}
fn strong(&self) -> &Cell<usize> {
unsafe { &self.ptr.as_ref().strong }
}
fn arc(&self) -> &Arc<T> {
assert_eq!(
mem::size_of::<Arc<T>>(),
mem::size_of::<Option<Arc<T>>>(),
"Error within drc::Drc<T>: Null pointer optimization does not apply to Arc<T>! If you \
see this panic, please report it to the maintainer(s) of the \"drc\" crate."
);
unsafe { &*(&self.ptr.as_ref().strong_ref as *const _ as *const Arc<T>) }
}
unsafe fn arc_mut(&mut self) -> &mut Arc<T> {
assert_eq!(
mem::size_of::<Arc<T>>(),
mem::size_of::<Option<Arc<T>>>(),
"Error within drc::Drc<T>: Null pointer optimization does not apply to Arc<T>! If you \
see this panic, please report it to the maintainer(s) of the \"drc\" crate."
);
&mut *(&mut self.ptr.as_mut().strong_ref as *mut _ as *mut Arc<T>)
}
unsafe fn take_arc(&self) -> Arc<T> {
assert_eq!(
mem::size_of::<Arc<T>>(),
mem::size_of::<Option<Arc<T>>>(),
"Error within drc::Drc<T>: Null pointer optimization does not apply to Arc<T>! If you \
see this panic, please report it to the maintainer(s) of the \"drc\" crate."
);
let storage = self.ptr.as_ptr();
let arc = ptr::read(&(*storage).strong_ref as *const _ as *const Arc<T>);
ptr::write(&mut (*storage).strong_ref, None);
arc
}
unsafe fn set_arc(&self, arc: Arc<T>) {
assert_eq!(
mem::size_of::<Arc<T>>(),
mem::size_of::<Option<Arc<T>>>(),
"Error within drc::Drc<T>: Null pointer optimization does not apply to Arc<T>! If you \
see this panic, please report it to the maintainer(s) of the \"drc\" crate."
);
ptr::write(
&mut (*self.ptr.as_ptr()).strong_ref as *mut _ as *mut Arc<T>,
arc,
);
}
}
impl<T> Clone for Drc<T>
where
T: ?Sized,
{
fn clone(&self) -> Drc<T> {
self.strong().set(self.strong().get() + 1);
Drc {
ptr: self.ptr,
phantom: PhantomData,
}
}
}
impl<T> Drop for Drc<T>
where
T: ?Sized,
{
fn drop(&mut self) {
unsafe {
let strong = self.strong().get();
self.strong().set(strong - 1);
if strong == 1
{
drop(self.take_arc());
let weak = self.weak().get();
self.weak().set(weak - 1);
if weak == 1
{
Box::from_raw(self.ptr.as_ptr());
}
}
}
}
}
impl<T> AsRef<T> for Drc<T>
where
T: ?Sized,
{
fn as_ref(&self) -> &T {
&**self
}
}
impl<T> Borrow<T> for Drc<T>
where
T: ?Sized,
{
fn borrow(&self) -> &T {
&**self
}
}
impl<T> Default for Drc<T>
where
T: Default,
{
fn default() -> Drc<T> {
Drc::new(Default::default())
}
}
impl<T> Deref for Drc<T>
where
T: ?Sized,
{
type Target = T;
fn deref(&self) -> &T {
&**(self.arc())
}
}
impl<T> Eq for Drc<T>
where
T: Eq + ?Sized,
{
}
impl From<CString> for Drc<CStr> {
fn from(c_string: CString) -> Drc<CStr> {
Drc::from(Arc::from(c_string))
}
}
impl From<String> for Drc<str> {
fn from(string: String) -> Drc<str> {
Drc::from(Arc::from(string))
}
}
impl From<OsString> for Drc<OsStr> {
fn from(os_string: OsString) -> Drc<OsStr> {
Drc::from(Arc::from(os_string))
}
}
impl From<PathBuf> for Drc<Path> {
fn from(path: PathBuf) -> Drc<Path> {
Drc::from(Arc::from(path))
}
}
impl<'a> From<&'a CStr> for Drc<CStr> {
fn from(c_string: &'a CStr) -> Drc<CStr> {
Drc::from(Arc::from(c_string))
}
}
impl<'a> From<&'a str> for Drc<str> {
fn from(string: &'a str) -> Drc<str> {
Drc::from(Arc::from(string))
}
}
impl<'a> From<&'a OsStr> for Drc<OsStr> {
fn from(os_string: &'a OsStr) -> Drc<OsStr> {
Drc::from(Arc::from(os_string))
}
}
impl<'a> From<&'a Path> for Drc<Path> {
fn from(path: &'a Path) -> Drc<Path> {
Drc::from(Arc::from(path))
}
}
impl<'a, T> From<&'a [T]> for Drc<[T]>
where
T: Clone,
{
fn from(slice: &'a [T]) -> Drc<[T]> {
Drc::from(Arc::from(slice))
}
}
impl<T> From<Arc<T>> for Drc<T>
where
T: ?Sized,
{
fn from(arc: Arc<T>) -> Drc<T> {
Drc::from_arc(arc)
}
}
impl<T> From<Box<T>> for Drc<T>
where
T: ?Sized,
{
fn from(box_: Box<T>) -> Drc<T> {
Drc::from(Arc::from(box_))
}
}
impl<T> From<T> for Drc<T> {
fn from(value: T) -> Drc<T> {
Drc::from(Arc::from(value))
}
}
impl<T> From<Vec<T>> for Drc<[T]> {
fn from(vec: Vec<T>) -> Drc<[T]> {
Drc::from(Arc::from(vec))
}
}
impl<T> Hash for Drc<T>
where
T: Hash + ?Sized,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
(**self).hash(state);
}
}
impl<T> Ord for Drc<T>
where
T: Ord + ?Sized,
{
#[inline]
fn cmp(&self, other: &Drc<T>) -> Ordering {
(**self).cmp(&**other)
}
}
impl<T> PartialEq<Drc<T>> for Drc<T>
where
T: PartialEq<T> + ?Sized,
{
fn eq(&self, other: &Drc<T>) -> bool {
**self == **other
}
fn ne(&self, other: &Drc<T>) -> bool {
**self != **other
}
}
impl<T> PartialOrd<Drc<T>> for Drc<T>
where
T: PartialOrd<T> + ?Sized,
{
#[inline(always)]
fn partial_cmp(&self, other: &Drc<T>) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
#[inline(always)]
fn lt(&self, other: &Drc<T>) -> bool {
**self < **other
}
#[inline(always)]
fn le(&self, other: &Drc<T>) -> bool {
**self <= **other
}
#[inline(always)]
fn gt(&self, other: &Drc<T>) -> bool {
**self > **other
}
#[inline(always)]
fn ge(&self, other: &Drc<T>) -> bool {
**self >= **other
}
}
impl<T> Debug for Drc<T>
where
T: Debug + ?Sized,
{
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{:?}", &**self)
}
}
impl<T> Display for Drc<T>
where
T: Display + ?Sized,
{
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{}", &**self)
}
}
impl<T> Pointer for Drc<T>
where
T: ?Sized,
{
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{:p}", &**self)
}
}
impl<T> UnwindSafe for Drc<T>
where
T: RefUnwindSafe + ?Sized,
{
}
pub(crate) struct DrcInner<T>
where
T: ?Sized,
{
pub(crate) strong: Cell<usize>,
pub(crate) weak: Cell<usize>,
pub(crate) strong_ref: Option<Arc<T>>,
pub(crate) weak_ref: Option<WeakArc<T>>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new() {
let drc = Drc::new(17usize);
let storage = unsafe { drc.ptr.as_ref() };
assert_eq!(
storage.strong.get(),
1,
"new Drc did not have strong count of 1."
);
assert_eq!(
storage.weak.get(),
1,
"new Drc did not have weak count of 1 (implicit)."
);
assert!(
storage.strong_ref.is_some(),
"new Drc did not have a stored Arc."
);
assert!(storage.weak_ref.is_none(), "new Drc had a stored WeakArc.");
let strong_ref = storage.strong_ref.as_ref().unwrap();
assert_eq!(**strong_ref, 17usize, "new Drc stored value incorrectly.");
assert_eq!(
Arc::strong_count(strong_ref),
1,
"internal Arc had an unexpected strong reference count."
);
assert_eq!(
Arc::weak_count(strong_ref),
0,
"internal Arc had an unexpected weak reference count."
);
}
#[test]
fn detach() {
let drc = Drc::new(17usize);
let storage = unsafe { drc.ptr.as_ref() };
let arc_ptr = &**storage.strong_ref.as_ref().unwrap() as *const _;
let new_arc = Drc::detach(&drc);
assert_eq!(
unsafe { drc.ptr.as_ref() } as *const _,
storage as *const _,
"original Drc changed pointer location when detached."
);
assert_eq!(
&*new_arc as *const _, arc_ptr,
"detached Arc did not have the same pointer value as original Drc."
);
}
#[test]
fn separate() {
let drc_1 = Drc::new(17usize);
let storage_1 = unsafe { drc_1.ptr.as_ref() };
let data_pointer_1 = &**storage_1.strong_ref.as_ref().unwrap() as *const _;
let drc_2 = Drc::separate(&drc_1);
let storage_2 = unsafe { drc_2.ptr.as_ref() };
let data_pointer_2 = &**storage_2.strong_ref.as_ref().unwrap() as *const _;
assert_eq!(
unsafe { drc_1.ptr.as_ref() } as *const _,
storage_1 as *const _,
"original Drc changed local storage location when separated."
);
assert_eq!(
&**storage_1.strong_ref.as_ref().unwrap() as *const _,
data_pointer_1,
"original Drc changed data pointer location when separated."
);
assert_ne!(
storage_1 as *const _, storage_2 as *const _,
"new Drc still shared local storage location with original Drc when separated."
);
assert_eq!(
data_pointer_1, data_pointer_2,
"new Drc did not share data pointer location with original Drc when separated."
);
assert_eq!(
storage_1.strong.get(),
1,
"original Drc had a different strong reference count than expected when separated."
);
assert_eq!(
storage_1.weak.get(),
1,
"original Drc had a different weak reference count than expected when separated."
);
assert!(
storage_1.weak_ref.is_none(),
"original Drc had a WeakArc stored when separated."
);
assert_eq!(
storage_2.strong.get(),
1,
"new Drc had a different strong reference count than expected."
);
assert_eq!(
storage_2.weak.get(),
1,
"new Drc had a different weak reference count than expected."
);
assert!(
storage_2.weak_ref.is_none(),
"new Drc had a WeakArc stored."
);
}
#[test]
fn try_unwrap() {
let x = Drc::new(3);
assert_eq!(Drc::try_unwrap(x), Ok(3));
let x = Drc::new(4);
let _y = Drc::clone(&x);
assert_eq!(*Drc::try_unwrap(x).unwrap_err(), 4);
let x = Drc::new(5);
let _y = Drc::detach(&x);
assert_eq!(*Drc::try_unwrap(x).unwrap_err(), 5);
}
#[test]
fn downgrade() {
let drc = Drc::new(17usize);
let drc_storage = unsafe { drc.ptr.as_ref() };
let weak = Drc::downgrade(&drc);
let weak_storage = unsafe { weak.ptr.as_ref() };
assert_eq!(
unsafe { drc.ptr.as_ref() } as *const _,
drc_storage as *const _,
"Drc changed local storage location when downgraded."
);
assert_eq!(
drc_storage as *const _, weak_storage as *const _,
"Drc did not share a storage location with new, weak Drc when downgraded."
);
assert!(
drc_storage.strong_ref.is_some(),
"Drc storage lost its strong reference when downgraded."
);
assert!(
drc_storage.weak_ref.is_some(),
"Drc storage did not gain a weak reference when downgraded."
);
assert_eq!(
drc_storage.strong.get(),
1,
"Drc had a different strong reference count than expected when downgraded."
);
assert_eq!(
drc_storage.weak.get(),
2,
"Drc had a different weak reference count than expected when downgraded."
);
let strong_ref = drc_storage.strong_ref.as_ref().unwrap();
assert_eq!(
Arc::strong_count(strong_ref),
1,
"internal Arc had an unexpected strong reference count when Drc downgraded."
);
assert_eq!(
Arc::weak_count(strong_ref),
1,
"internal Arc had an unexpected weak reference count when Drc downgraded."
);
let _weak_2 = Drc::downgrade(&drc);
assert_eq!(
unsafe { drc.ptr.as_ref() } as *const _,
drc_storage as *const _,
"original Drc changed local storage location when downgraded a second time."
);
assert!(
drc_storage.strong_ref.is_some(),
"Drc storage lost its strong reference when downgraded a second time."
);
assert!(
drc_storage.weak_ref.is_some(),
"Drc storage did not gain a weak reference when downgraded a second time."
);
assert_eq!(
drc_storage.strong.get(),
1,
"Drc had a different strong reference count than expected when downgraded a second \
time."
);
assert_eq!(
drc_storage.weak.get(),
3,
"Drc had a different weak reference count than expected when downgraded a second time."
);
assert_eq!(
drc_storage.strong_ref.as_ref().unwrap() as *const _,
strong_ref as *const _,
"Drc had a different internal strong Arc when downgraded a second time."
);
assert_eq!(
Arc::strong_count(strong_ref),
1,
"internal Arc had an unexpected strong reference count when Drc downgraded a second \
time."
);
assert_eq!(
Arc::weak_count(strong_ref),
1,
"internal Arc had an unexpected weak reference count when Drc downgraded a second \
time."
);
}
#[test]
fn weak_count() {
let five = Drc::new(5);
let _weak_five_a = Drc::downgrade(&five);
let _weak_five_b = Drc::downgrade(&five);
let _weak_five_c = Drc::downgrade(&five);
let _separate_five = Drc::separate(&five);
let detached_five = Drc::detach(&five);
let _weak_detached_five = Arc::downgrade(&detached_five);
assert_eq!(3, Drc::weak_count(&five, true));
assert_eq!(2, Drc::weak_count(&five, false));
}
#[test]
fn strong_count() {
let five = Drc::new(5);
let _also_five = Drc::clone(&five);
let _still_five = Drc::clone(&five);
let _weak_separate_five = {
let separate_five = Drc::separate(&five);
Drc::downgrade(&separate_five)
};
let _strong_separate_five = Drc::separate(&five);
let detached_five = Drc::detach(&five);
let _also_detached_five = Arc::clone(&detached_five);
assert_eq!(3, Drc::strong_count(&five, true));
assert_eq!(4, Drc::strong_count(&five, false));
}
#[test]
fn get_mut() {
{
let mut drc = Drc::new(17usize);
*Drc::get_mut(&mut drc).unwrap() = 117usize;
assert_eq!(*drc, 117usize, "Intended Drc get_mut mutation failed.");
}
{
{
let mut drc = Drc::new(17usize);
let mut drc_clone = Drc::clone(&drc);
assert!(
Drc::get_mut(&mut drc).is_none(),
"Drc::get_mut returned Some(_) when another local Drc existed."
);
assert!(
Drc::get_mut(&mut drc_clone).is_none(),
"Drc::get_mut returned Some(_) on Drc clone when original Drc existed."
);
}
{
let mut drc = Drc::new(17usize);
let mut drc_separate = Drc::separate(&drc);
assert!(
Drc::get_mut(&mut drc).is_none(),
"Drc::get_mut returned Some(_) when another nonlocal Drc existed."
);
assert!(
Drc::get_mut(&mut drc_separate).is_none(),
"Drc::get_mut returned Some(_) on separate Drc when original Drc existed."
);
}
}
{
let mut drc = Drc::new(17usize);
let _arc = Drc::detach(&drc);
assert!(
Drc::get_mut(&mut drc).is_none(),
"Drc::get_mut returned Some(_) when another Arc existed."
);
}
{
{
let mut drc = Drc::new(17usize);
let weak_drc = Drc::downgrade(&drc);
assert!(
Drc::get_mut(&mut drc).is_none(),
"Drc::get_mut returned Some(_) when a local weak Drc existed."
);
assert!(
Drc::get_mut(&mut Weak::upgrade(&weak_drc).unwrap()).is_none(),
"Drc::get_mut returned Some(_) on upgraded local weak Drc when original Drc \
existed."
);
}
{
let mut drc = Drc::new(17usize);
let weak_drc = Drc::downgrade(&Drc::separate(&drc));
assert!(
Drc::get_mut(&mut drc).is_none(),
"Drc::get_mut returned Some(_) when a nonlocal Drc existed."
);
assert!(
Drc::get_mut(&mut Weak::upgrade(&weak_drc).unwrap()).is_none(),
"Drc::get_mut returned Some(_) on upgraded nonlocal weak Drc when original \
Drc existed."
);
}
}
{
{
let mut drc = Drc::new(17usize);
let weak_arc = Arc::downgrade(&Drc::detach(&drc));
assert!(
Drc::get_mut(&mut drc).is_none(),
"Drc::get_mut returned Some(_) when a weak Arc existed."
);
assert!(
Arc::get_mut(&mut WeakArc::upgrade(&weak_arc).unwrap()).is_none(),
"Arc::get_mut returned Some(_) on upgraded weak Arc when original Drc existed."
);
}
{
let mut drc = Drc::new(17usize);
let weak_arc = Weak::detach(&Drc::downgrade(&drc));
assert!(
Drc::get_mut(&mut drc).is_none(),
"Drc::get_mut returned Some(_) when a weak Arc existed."
);
assert!(
Arc::get_mut(&mut WeakArc::upgrade(&weak_arc).unwrap()).is_none(),
"Arc::get_mut returned Some(_) on upgraded weak Arc when original Drc existed."
);
}
}
}
#[test]
fn ptr_eq() {
{
{
let (drc_1, drc_2): (Drc<usize>, Drc<usize>) = {
let arc = Arc::new(17usize);
let drc_1 = Drc::from(Arc::clone(&arc));
(drc_1, Drc::from(arc))
};
assert!(
Drc::ptr_eq(&drc_1, &drc_2),
"Drcs created from two associated Arcs were not pointer equal."
);
}
{
let drc_1: Drc<usize> = Drc::from(Arc::new(17usize));
let drc_2: Drc<usize> = Drc::from(Arc::new(17usize));
assert!(
!Drc::ptr_eq(&drc_1, &drc_2),
"Drcs created from two separate Arcs were pointer equal."
);
}
}
{
{
let drc_1: Drc<usize> = Drc::new(17usize);
let drc_2: Drc<usize> = Drc::from(Drc::detach(&drc_1));
assert!(
Drc::ptr_eq(&drc_1, &drc_2),
"Separate Drcs created manually with 'detach' and 'from' were not pointer \
equal."
);
}
}
{
{
let drc_1 = Drc::new(17usize);
let drc_2 = Drc::separate(&drc_1);
assert!(
Drc::ptr_eq(&drc_1, &drc_2),
"Separate Drcs created with 'separate' were not pointer equal."
);
}
}
{
{
let drc_1 = Drc::new(17usize);
let drc_2 = Drc::clone(&drc_1);
assert!(
Drc::ptr_eq(&drc_1, &drc_2),
"Linked Drcs created with 'clone' were not pointer equal."
);
}
{
let drc_1 = Drc::new(17usize);
let drc_2 = Drc::new(17usize);
assert!(
!Drc::ptr_eq(&drc_1, &drc_2),
"Drcs created using two separate 'new' calls were pointer equal."
);
}
}
}
#[test]
fn arc_ptr_eq() {
{
{
let arc: Arc<usize> = Arc::new(17usize);
let drc: Drc<usize> = Drc::from(Arc::clone(&arc));
assert!(
Drc::arc_ptr_eq(&drc, &arc),
"An Arc and a Drc created from the Arc's clone were not pointer equal."
);
}
{
let arc: Arc<usize> = Arc::new(17usize);
let drc: Drc<usize> = Drc::from(Arc::new(17usize));
assert!(
!Drc::arc_ptr_eq(&drc, &arc),
"An Arc and a Drc created from a different Arc were pointer equal."
);
}
}
{
{
let drc = Drc::new(17usize);
let arc = Drc::detach(&drc);
assert!(
Drc::arc_ptr_eq(&drc, &arc),
"A Drc and an Arc detached from the Drc were not pointer equal."
);
}
{
let drc = Drc::new(17usize);
let arc = Drc::detach(&Drc::new(17usize));
assert!(
!Drc::arc_ptr_eq(&drc, &arc),
"A Drc and an Arc detached from a different Drc were pointer equal"
);
}
}
{
{
let drc = Drc::new(17usize);
let arc = Drc::detach(&Drc::separate(&drc));
assert!(
Drc::arc_ptr_eq(&drc, &arc),
"A Drc and an Arc detached from a Drc separated from the original Drc were \
not pointer equal."
);
}
{
let drc = Drc::new(17usize);
let arc = Drc::detach(&Drc::separate(&Drc::new(17usize)));
assert!(
!Drc::arc_ptr_eq(&drc, &arc),
"A Drc and an Arc detached from a Drc separated from a different Drc were \
pointer equal."
);
}
}
{
{
let drc = Drc::new(17usize);
let arc = Drc::detach(&Drc::clone(&drc));
assert!(
Drc::arc_ptr_eq(&drc, &arc),
"A Drc and an Arc detached from a clone of the Drc were not pointer equal."
);
}
{
let drc = Drc::new(17usize);
let arc = Drc::detach(&Drc::clone(&Drc::new(17usize)));
assert!(
!Drc::arc_ptr_eq(&drc, &arc),
"A Drc and an Arc detached from a clone of a different Drc were pointer equal."
);
}
}
}
#[test]
fn linked() {
{
let drc_1 = Drc::new(17usize);
let drc_2 = Drc::clone(&drc_1);
assert!(
Drc::linked(&drc_1, &drc_2),
"Two Drcs that were the strict definition of 'linked' were not considered linked."
);
}
{
{
let (drc_1, drc_2): (Drc<usize>, Drc<usize>) = {
let arc = Arc::new(17usize);
let drc_1 = Drc::from(Arc::clone(&arc));
(drc_1, Drc::from(arc))
};
assert!(
!Drc::linked(&drc_1, &drc_2),
"Two Drcs separated due to being created from two different but associated \
Arcs were considered linked."
);
}
{
let drc_1: Drc<usize> = Drc::from(Arc::new(17usize));
let drc_2: Drc<usize> = Drc::from(Arc::new(17usize));
assert!(
!Drc::linked(&drc_1, &drc_2),
"Two Drcs separated due to being created from two different and unassociated \
Arcs were considered linked."
);
}
}
{
let drc_1: Drc<usize> = Drc::new(17usize);
let drc_2: Drc<usize> = Drc::from(Drc::detach(&drc_1));
assert!(
!Drc::linked(&drc_1, &drc_2),
"Two Drcs separated due to one being detached from the other and then converted \
back into a Drc were considered linked."
);
}
{
let drc_1 = Drc::new(17usize);
let drc_2 = Drc::separate(&drc_1);
assert!(
!Drc::linked(&drc_1, &drc_2),
"Two Drcs separated with the 'separate' method were considered linked."
);
}
{
{
let drc_1 = Drc::new(17usize);
let drc_2 = Drc::new(17usize);
assert!(
!Drc::linked(&drc_1, &drc_2),
"Two Drcs separated due to being made with separate 'new' calls were \
considered linked."
);
}
{
let drc_1: Drc<usize> = Drc::new(17usize);
let drc_2: Drc<usize> = Drc::from(Arc::new(17usize));
assert!(
!Drc::linked(&drc_1, &drc_2),
"Two Drcs separated due to one being made with 'new' and the other made with \
'Drc::from(arc)' were considered linked."
);
}
}
}
#[test]
fn make_mut() {
{
let mut drc = Drc::new(17usize);
let storage = drc.ptr.as_ptr();
*Drc::get_mut(&mut drc).unwrap() = 117usize;
assert_eq!(*drc, 117usize, "Intended Drc make_mut mutation failed.");
assert_eq!(
storage,
drc.ptr.as_ptr(),
"Drc storage changed with make_mut when it should not have."
);
}
{
{
let mut drc = Drc::new(17usize);
let mut drc_clone = Drc::clone(&drc);
let storage = drc.ptr.as_ptr();
let val_ptr = &*drc as *const _;
*Drc::make_mut(&mut drc) = 117usize;
assert_eq!(*drc, 117usize, "Intended Drc make_mut mutation failed.");
assert_eq!(*drc_clone, 17usize, "Drc make_mut mutation affected clone.");
assert_ne!(
storage,
drc.ptr.as_ptr(),
"Drc make_mut did not change storage when it should have."
);
assert_eq!(
storage,
drc_clone.ptr.as_ptr(),
"Drc make_mut changed storage for clone when it should not have."
);
assert_eq!(
unsafe { &**(*storage).strong_ref.as_ref().unwrap() } as *const _,
val_ptr,
"Drc make_mut changed original storage's Arc pointer when it should not have."
);
*Drc::make_mut(&mut drc_clone) = 1117usize;
assert_eq!(
*drc_clone, 1117usize,
"Intended Drc clone make_mut mutation failed."
);
assert_eq!(
storage,
drc_clone.ptr.as_ptr(),
"Drc clone make_mut changed storage when it should not have."
);
}
{
let mut drc = Drc::new(17usize);
let mut drc_separate = Drc::separate(&drc);
let original_storage = drc.ptr.as_ptr();
let separate_storage = drc_separate.ptr.as_ptr();
let original_storage_ref = unsafe { (&*original_storage) };
let separate_storage_ref = unsafe { (&*separate_storage) };
let val_ptr = &*drc as *const _;
assert!(
Arc::ptr_eq(
original_storage_ref.strong_ref.as_ref().unwrap(),
separate_storage_ref.strong_ref.as_ref().unwrap()
),
"Values should be linked."
);
*Drc::make_mut(&mut drc) = 117usize;
assert_eq!(*drc, 117usize, "Intended Drc make_mut mutation failed.");
assert_eq!(
*drc_separate, 17usize,
"Drc make_mut mutation affected separated Drc."
);
assert_eq!(
original_storage,
drc.ptr.as_ptr(),
"Drc make_mut changed storage when it should not have."
);
assert_eq!(
separate_storage,
drc_separate.ptr.as_ptr(),
"Drc make_mut changed storage for separate Drc when it should not have."
);
{
let original_storage_arc = original_storage_ref.strong_ref.as_ref().unwrap();
let separate_storage_arc = separate_storage_ref.strong_ref.as_ref().unwrap();
assert!(
!Arc::ptr_eq(original_storage_arc, separate_storage_arc),
"Drc make_mut did not change Arcs."
);
assert_eq!(
&*drc_separate as *const _, val_ptr,
"Drc make_mut changed value pointer for separate Drc when it should not \
have."
);
assert_eq!(
Arc::strong_count(original_storage_arc),
1,
"Drc make_mut did not update strong count properly."
);
assert_eq!(
Arc::strong_count(separate_storage_arc),
1,
"Drc make_mut did not update strong count properly."
);
}
*Drc::make_mut(&mut drc_separate) = 1117usize;
assert_eq!(
*drc_separate, 1117usize,
"Intended separate Drc make_mut mutation failed."
);
assert_eq!(
separate_storage,
drc_separate.ptr.as_ptr(),
"Separate Drc make_mut changed storage when it should not have."
);
assert_eq!(
&*drc_separate as *const _, val_ptr,
"Separate Drc make_mut changed value pointer when it should not have."
);
}
}
{
{
let mut drc = Drc::new(17usize);
let mut arc = Drc::detach(&drc);
let original_storage = drc.ptr.as_ptr();
let val_ptr = &*drc as *const _;
assert!(
Drc::arc_ptr_eq(&drc, &arc),
"Values should be pointer equal."
);
*Drc::make_mut(&mut drc) = 117usize;
assert_eq!(*drc, 117usize, "Intended Drc make_mut mutation failed.");
assert_eq!(
*arc, 17usize,
"Drc make_mut mutation affected detached Arc."
);
assert_eq!(
original_storage,
drc.ptr.as_ptr(),
"Drc make_mut mutation changed storage when it should not have."
);
assert_eq!(
&*arc as *const _, val_ptr,
"Drc make_mut mutation changed Arc value pointer when it should not have."
);
*Arc::make_mut(&mut arc) = 1117usize;
assert_eq!(
*arc, 1117usize,
"Intended detached Arc make_mut mutation failed."
);
assert_eq!(
&*arc as *const _, val_ptr,
"Detached Arc make_mut mutation changed value pointer when it should not have."
);
}
{
let mut drc = Drc::new(17usize);
let arc = Drc::detach(&drc);
let original_storage = drc.ptr.as_ptr();
let val_ptr = &*drc as *const _;
assert!(
Drc::arc_ptr_eq(&drc, &arc),
"Values should be pointer equal."
);
let drc = {
let weak = Drc::downgrade(&drc);
*Drc::make_mut(&mut drc) = 117usize;
assert_eq!(*drc, 117usize, "Intended Drc make_mut mutation failed.");
assert_eq!(
*arc, 17usize,
"Drc make_mut mutation affected detached Arc."
);
assert_ne!(
original_storage,
drc.ptr.as_ptr(),
"Drc make_mut mutation did not change storage when it should have."
);
assert_eq!(
original_storage,
weak.ptr.as_ptr(),
"Drc make_mut mutation changed weak pointer storage when it should not \
have."
);
assert_eq!(
&*arc as *const _, val_ptr,
"Drc make_mut mutation changed Arc value pointer when it should not have."
);
weak.upgrade().unwrap()
};
assert_eq!(
&*drc as *const _, val_ptr,
"Drc make_mut mutation altered (now-upgraded) weak pointer pointer location."
);
}
}
{
{
let mut drc = Drc::new(17usize);
let original_storage = drc.ptr.as_ptr();
let val_ptr = &*drc as *const _;
let weak = Drc::downgrade(&drc);
*Drc::make_mut(&mut drc) = 117usize;
assert_eq!(*drc, 117usize, "Intended Drc make_mut mutation failed.");
assert_ne!(
original_storage,
drc.ptr.as_ptr(),
"Drc make_mut mutation did not change storage when it should have."
);
assert_eq!(
original_storage,
weak.ptr.as_ptr(),
"Drc make_mut mutation changed weak pointer storage when it should not have."
);
assert_ne!(
&*drc as *const _, val_ptr,
"Drc make_mut mutation did not change value pointer when it should have."
);
assert!(
weak.upgrade().is_none(),
"Drc make_mut mutation should have removed the only strong pointer to the \
original value, thus invalidating the weak pointer."
);
}
{
for i in 0usize..3usize {
let mut drc = Drc::new(17usize);
let original_storage = drc.ptr.as_ptr();
let val_ptr = &*drc as *const _;
let weak = match i {
0 => Drc::downgrade(&Drc::separate(&drc)),
1 => Drc::downgrade(&Drc::from(Drc::detach(&drc))),
2 => Weak::with_weak_arc(Arc::downgrade(&Drc::detach(&drc))),
_ => unreachable!(),
};
let separate_storage = weak.ptr.as_ptr();
*Drc::make_mut(&mut drc) = 117usize;
assert_eq!(*drc, 117usize, "Intended Drc make_mut mutation failed.");
assert_eq!(
original_storage,
drc.ptr.as_ptr(),
"Drc make_mut mutation changed storage when it should not have."
);
assert_eq!(
separate_storage,
weak.ptr.as_ptr(),
"Drc make_mut mutation changed weak pointer storage when it should not \
have."
);
assert_ne!(
&*drc as *const _, val_ptr,
"Drc make_mut mutation did not change value pointer when it should have."
);
assert!(
weak.upgrade().is_none(),
"Drc make_mut mutation should have removed the only strong pointer to the \
original value, thus invalidating the weak pointer."
);
}
}
}
{
for i in 0usize..2usize {
let mut drc = Drc::new(17usize);
let original_storage = drc.ptr.as_ptr();
let val_ptr = &*drc as *const _;
let weak = match i {
0 => Arc::downgrade(&Drc::detach(&drc)),
1 => Drc::downgrade(&drc).detach(),
_ => unreachable!(),
};
*Drc::make_mut(&mut drc) = 117usize;
assert_eq!(*drc, 117usize, "Intended Drc make_mut mutation failed.");
assert_eq!(
original_storage,
drc.ptr.as_ptr(),
"Drc make_mut mutation changed storage when it should not have."
);
assert_ne!(
&*drc as *const _, val_ptr,
"Drc make_mut mutation did not change value pointer when it should have."
);
assert!(
weak.upgrade().is_none(),
"Drc make_mut mutation should have removed the only strong pointer to the \
original value, thus invalidating the weak pointer."
);
}
}
}
#[test]
fn clone() {
let five = Drc::new(5);
let same_five = Drc::clone(&five);
assert!(Drc::linked(&five, &same_five));
assert_eq!(2, Drc::strong_count(&five, true));
assert_eq!(1, Drc::strong_count(&five, false));
}
#[test]
fn drop() {
struct Foo<'a>(&'a Cell<bool>);
impl<'a> Drop for Foo<'a> {
fn drop(&mut self) {
self.0.set(true);
}
}
let cell = Cell::new(false);
let foo = Drc::new(Foo(&cell));
let foo2 = Drc::clone(&foo);
assert_eq!(cell.get(), false);
mem::drop(foo);
assert_eq!(cell.get(), false);
mem::drop(foo2);
assert_eq!(cell.get(), true);
}
#[test]
fn debug() {
let drc = Drc::new(17usize);
assert_eq!(
format!("{:?}", &*drc),
format!("{:?}", &drc),
"Debug outputs of actual value and Drc are not equal!"
);
}
#[test]
fn display() {
let drc = Drc::new(17usize);
assert_eq!(
format!("{}", &*drc),
format!("{}", &drc),
"Display outputs of actual value and Drc are not equal!"
);
}
#[test]
fn pointer() {
let drc = Drc::new(17usize);
assert_eq!(
format!("{:p}", &*drc),
format!("{:p}", drc),
"Pointer outputs of smart value and Drc are not equal!"
);
}
}