Created
April 27, 2015 21:05
-
-
Save rkjnsn/642766e1d81925e2540b to your computer and use it in GitHub Desktop.
Experiment with creating NoCycleRc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::boxed; | |
use std::cell::Cell; | |
use std::cmp::Ordering; | |
use std::fmt; | |
use std::hash::{Hasher, Hash}; | |
use std::marker::PhantomData; | |
use std::mem::{forget, min_align_of, size_of}; | |
use std::ops::Deref; | |
use std::ptr; | |
use std::rt::heap::deallocate; | |
struct RcBox<T> { | |
value: T, | |
strong: Cell<usize>, | |
weak: Cell<usize> | |
} | |
/// A reference-counted pointer type over an immutable value. | |
/// | |
/// See the [module level documentation](./index.html) for more details. | |
pub struct NoCycleRc<'a, T> { | |
// FIXME #12808: strange names to try to avoid interfering with field | |
// accesses of the contained type via Deref | |
_ptr: *mut RcBox<T>, | |
_marker: PhantomData<&'a ()>, // 'a is contravariant | |
} | |
//impl<'a, T> !Send for NoCycleRc<'a, T> {} | |
//impl<'a, T> !Sync for NoCycleRc<'a, T> {} | |
impl<'a, T> NoCycleRc<'a, T> { | |
fn priv_new(value: T) -> NoCycleRc<'a, T> { | |
NoCycleRc { | |
// there is an implicit weak pointer owned by all the strong | |
// pointers, which ensures that the weak destructor never frees | |
// the allocation while the strong destructor is running, even | |
// if the weak pointer is stored inside the strong one. | |
_ptr: unsafe { boxed::into_raw(Box::new(RcBox { | |
value: value, | |
strong: Cell::new(1), | |
weak: Cell::new(1) | |
})) }, | |
_marker: PhantomData, | |
} | |
} | |
/// Downgrades the `NoCycleRc<'a, T>` to a `NoCycleWeak<'a, T>` reference. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// let five = marker.new_rc(5); | |
/// | |
/// let weak_five = five.downgrade(); | |
/// ``` | |
pub fn downgrade(&self) -> NoCycleWeak<'a, T> { | |
self.inc_weak(); | |
NoCycleWeak { _ptr: self._ptr, _marker: PhantomData } | |
} | |
} | |
/// Get the number of weak references to this value. | |
#[inline] | |
pub fn weak_count<'a, T>(this: &NoCycleRc<'a, T>) -> usize { this.weak() - 1 } | |
/// Get the number of strong references to this value. | |
#[inline] | |
pub fn strong_count<'a, T>(this: &NoCycleRc<'a, T>) -> usize { this.strong() } | |
/// Returns true if there are no other `NoCycleRc` or `NoCycleWeak` values | |
/// that share the same inner value. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{self, NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// let five = marker.new_rc(5); | |
/// | |
/// nocyclerc::is_unique(&five); | |
/// ``` | |
#[inline] | |
pub fn is_unique<'a, T>(rc: &NoCycleRc<'a, T>) -> bool { | |
weak_count(rc) == 0 && strong_count(rc) == 1 | |
} | |
/// Unwraps the contained value if the `NoCycleRc<'a, T>` is the only strong | |
/// reference. | |
/// | |
/// Unlike get_mut, this works whenever `strong_count` is one, even if there | |
/// are weak references. If the `NoCycleRc<'a, T>` is not unique, an `Err` is | |
/// returned with the same `NoCycleRc<'a, T>`. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{self, NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let x = marker.new_rc(3); | |
/// assert_eq!(rc::try_unwrap(x), Ok(3)); | |
/// | |
/// let x = marker.new_rc(4); | |
/// let _y = x.clone(); | |
/// assert_eq!(nocyclerc::try_unwrap(x), Err(marker.new_rc(4))); | |
/// ``` | |
#[inline] | |
pub fn try_unwrap<'a, T>(rc: NoCycleRc<'a, T>) -> Result<T, NoCycleRc<'a, T>> { | |
if strong_count(&rc) == 1 { | |
unsafe { | |
rc.dec_strong(); | |
// We know strong count is now 0 | |
let val = ptr::read(&rc.inner().value); // copy the contained object | |
// remove the implicit "strong weak" pointer now that we've | |
// removed the contents. | |
rc.dec_weak(); | |
if rc.weak() == 0 { | |
deallocate(rc._ptr as *mut u8, size_of::<RcBox<T>>(), | |
min_align_of::<RcBox<T>>()); | |
} | |
// Skip our Drop | |
forget(rc); | |
Ok(val) | |
} | |
} else { | |
Err(rc) | |
} | |
} | |
/// Returns a mutable reference to the contained value if the | |
/// `NoCycleRc<'a, T>` is unique. | |
/// | |
/// Returns `None` if the `NoCycleRc<'a, T>` is not unique. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{self, NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let mut x = marker.new_rc(3); | |
/// *nocyclerc::get_mut(&mut x).unwrap() = 4; | |
/// assert_eq!(*x, 4); | |
/// | |
/// let _y = x.clone(); | |
/// assert!(nocyclerc::get_mut(&mut x).is_none()); | |
/// ``` | |
#[inline] | |
pub fn get_mut<'a, 'b, T>(rc: &'b mut NoCycleRc<'a, T>) -> Option<&'b mut T> { | |
if is_unique(rc) { | |
let inner = unsafe { &mut *rc._ptr }; | |
Some(&mut inner.value) | |
} else { | |
None | |
} | |
} | |
impl<'a, T: Clone> NoCycleRc<'a, T> { | |
/// Make a mutable reference from the given `NoCycleRc<'a, T>`. | |
/// | |
/// This is also referred to as a copy-on-write operation because the inner | |
/// data is cloned if the reference count is greater than one. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let mut five = marker.new_rc(5); | |
/// | |
/// let mut_five = five.make_unique(); | |
/// ``` | |
#[inline] | |
pub fn make_unique(&mut self) -> &mut T { | |
if !is_unique(self) { | |
*self = NoCycleRc::priv_new((**self).clone()) | |
} | |
// This unsafety is ok because we're guaranteed that the pointer | |
// returned is the *only* pointer that will ever be returned to T. Our | |
// reference count is guaranteed to be 1 at this point, and we required | |
// the `NoCycleRc<'a, T>` itself to be `mut`, so we're returning the | |
// only possible reference to the inner value. | |
let inner = unsafe { &mut *self._ptr }; | |
&mut inner.value | |
} | |
} | |
impl<'a, T> Deref for NoCycleRc<'a, T> { | |
type Target = T; | |
#[inline(always)] | |
fn deref(&self) -> &T { | |
&self.inner().value | |
} | |
} | |
impl<'a, T> Drop for NoCycleRc<'a, T> { | |
/// Drops the `NoCycleRc<'a, T>`. | |
/// | |
/// This will decrement the strong reference count. If the strong reference | |
/// count becomes zero and the only other references are `NoCycleWeak` | |
/// ones, `drop`s the inner value. | |
fn drop(&mut self) { | |
unsafe { | |
let ptr = self._ptr; | |
self.dec_strong(); | |
if self.strong() == 0 { | |
ptr::read(&**self); // destroy the contained object | |
// remove the implicit "strong weak" pointer now that we've | |
// destroyed the contents. | |
self.dec_weak(); | |
if self.weak() == 0 { | |
deallocate(ptr as *mut u8, size_of::<RcBox<T>>(), | |
min_align_of::<RcBox<T>>()) | |
} | |
} | |
} | |
} | |
} | |
impl<'a, T> Clone for NoCycleRc<'a, T> { | |
/// Makes a clone of the `NoCycleRc<'a, T>`. | |
/// | |
/// When you clone an `NoCycleRc<'a, T>`, it will create another pointer to | |
/// the data and increase the strong reference counter. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let five = marker.new_rc(5); | |
/// | |
/// five.clone(); | |
/// ``` | |
#[inline] | |
fn clone(&self) -> NoCycleRc<'a, T> { | |
self.inc_strong(); | |
NoCycleRc { _ptr: self._ptr, _marker: PhantomData } | |
} | |
} | |
impl<'a, 'b, T: PartialEq> PartialEq<NoCycleRc<'b, T>> for NoCycleRc<'a, T> { | |
/// Equality for two `NoCycleRc<'a, T>`s. | |
/// | |
/// Two `NoCycleRc<'a, T>`s are equal if their inner value are equal. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let five = marker.new_rc(5); | |
/// | |
/// five == marker.new_rc(5); | |
/// ``` | |
#[inline(always)] | |
fn eq(&self, other: &NoCycleRc<'b, T>) -> bool { **self == **other } | |
/// Inequality for two `NoCycleRc<'a, T>`s. | |
/// | |
/// Two `NoCycleRc<'a, T>`s are unequal if their inner value are unequal. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let five = marker.new_rc(5); | |
/// | |
/// five != marker.new_rc(5); | |
/// ``` | |
#[inline(always)] | |
fn ne(&self, other: &NoCycleRc<'b, T>) -> bool { **self != **other } | |
} | |
impl<'a, T: Eq> Eq for NoCycleRc<'a, T> {} | |
impl<'a, 'b, T: PartialOrd> PartialOrd<NoCycleRc<'b, T>> for NoCycleRc<'a, T> { | |
/// Partial comparison for two `NoCycleRc<'a, T>`s. | |
/// | |
/// The two are compared by calling `partial_cmp()` on their inner values. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let five = marker.new_rc(5); | |
/// | |
/// five.partial_cmp(&marker.new_rc(5)); | |
/// ``` | |
#[inline(always)] | |
fn partial_cmp(&self, other: &NoCycleRc<'b, T>) -> Option<Ordering> { | |
(**self).partial_cmp(&**other) | |
} | |
/// Less-than comparison for two `NoCycleRc<'a, T>`s. | |
/// | |
/// The two are compared by calling `<` on their inner values. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let five = marker.new_rc(5); | |
/// | |
/// five < marker.new_rc(5); | |
/// ``` | |
#[inline(always)] | |
fn lt(&self, other: &NoCycleRc<'b, T>) -> bool { **self < **other } | |
/// 'Less-than or equal to' comparison for two `NoCycleRc<'a, T>`s. | |
/// | |
/// The two are compared by calling `<=` on their inner values. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let five = marker.new_rc(5); | |
/// | |
/// five <= marker.new_rc(5); | |
/// ``` | |
#[inline(always)] | |
fn le(&self, other: &NoCycleRc<'b, T>) -> bool { **self <= **other } | |
/// Greater-than comparison for two `NoCycleRc<'a, T>`s. | |
/// | |
/// The two are compared by calling `>` on their inner values. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let five = marker.new_rc(5); | |
/// | |
/// five > marker.new_rc(5); | |
/// ``` | |
#[inline(always)] | |
fn gt(&self, other: &NoCycleRc<'b, T>) -> bool { **self > **other } | |
/// 'Greater-than or equal to' comparison for two `NoCycleRc<'a, T>`s. | |
/// | |
/// The two are compared by calling `>=` on their inner values. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let five = marker.new_rc(5); | |
/// | |
/// five >= marker.new_rc(5); | |
/// ``` | |
#[inline(always)] | |
fn ge(&self, other: &NoCycleRc<'b, T>) -> bool { **self >= **other } | |
} | |
impl<'a, T: Ord> Ord for NoCycleRc<'a, T> { | |
/// Comparison for two `NoCycleRc<'a, T>`s. | |
/// | |
/// The two are compared by calling `cmp()` on their inner values. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let five = marker.new_rc(5); | |
/// | |
/// five.partial_cmp(&marker.new_rc(5)); | |
/// ``` | |
#[inline] | |
fn cmp(&self, other: &NoCycleRc<'a, T>) -> Ordering { (**self).cmp(&**other) } | |
} | |
// FIXME (#18248) Make `T` `Sized?` | |
impl<'a, T: Hash> Hash for NoCycleRc<'a, T> { | |
fn hash<H: Hasher>(&self, state: &mut H) { | |
(**self).hash(state); | |
} | |
} | |
impl<'a, T: fmt::Display> fmt::Display for NoCycleRc<'a, T> { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
fmt::Display::fmt(&**self, f) | |
} | |
} | |
impl<'a, T: fmt::Debug> fmt::Debug for NoCycleRc<'a, T> { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
fmt::Debug::fmt(&**self, f) | |
} | |
} | |
impl<'a, T> fmt::Pointer for NoCycleRc<'a, T> { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
fmt::Pointer::fmt(&self._ptr, f) | |
} | |
} | |
/// A weak version of `NoCycleRc<'a, T>`. | |
/// | |
/// Weak references do not count when determining if the inner value should be | |
/// dropped. | |
/// | |
/// See the [module level documentation](./index.html) for more. | |
pub struct NoCycleWeak<'a, T> { | |
// FIXME #12808: strange names to try to avoid interfering with | |
// field accesses of the contained type via Deref | |
_ptr: *mut RcBox<T>, | |
_marker: PhantomData<&'a ()>, // 'a is contravariant | |
} | |
//impl<'a, T> !Send for NoCycleWeak<'a, T> {} | |
//impl<'a, T> !Sync for NoCycleWeak<'a, T> {} | |
impl<'a, T> NoCycleWeak<'a, T> { | |
/// Upgrades a weak reference to a strong reference. | |
/// | |
/// Upgrades the `NoCycleWeak<'a, T>` reference to an `NoCycleRc<'a, T>`, | |
/// if possible. | |
/// | |
/// Returns `None` if there were no strong references and the data was | |
/// destroyed. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let five = marker.new_rc(5); | |
/// | |
/// let weak_five = five.downgrade(); | |
/// | |
/// let strong_five: Option<NoCycleRc<_>> = weak_five.upgrade(); | |
/// ``` | |
pub fn upgrade(&self) -> Option<NoCycleRc<'a, T>> { | |
if self.strong() == 0 { | |
None | |
} else { | |
self.inc_strong(); | |
Some(NoCycleRc { _ptr: self._ptr, _marker: PhantomData }) | |
} | |
} | |
} | |
impl<'a, T> Drop for NoCycleWeak<'a, T> { | |
/// Drops the `NoCycleWeak<'a, T>`. | |
/// | |
/// This will decrement the weak reference count. | |
fn drop(&mut self) { | |
unsafe { | |
let ptr = self._ptr; | |
self.dec_weak(); | |
// the weak count starts at 1, and will only go to zero if all | |
// the strong pointers have disappeared. | |
if self.weak() == 0 { | |
deallocate(ptr as *mut u8, size_of::<RcBox<T>>(), | |
min_align_of::<RcBox<T>>()) | |
} | |
} | |
} | |
} | |
impl<'a, T> Clone for NoCycleWeak<'a, T> { | |
/// Makes a clone of the `NoCycleWeak<'a, T>`. | |
/// | |
/// This increases the weak reference count. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use nocyclerc::{NoCycleMarker, NoCycleRc}; | |
/// | |
/// let marker = NoCycleMarker::new(); | |
/// | |
/// let weak_five = marker.new_rc(5).downgrade(); | |
/// | |
/// weak_five.clone(); | |
/// ``` | |
#[inline] | |
fn clone(&self) -> NoCycleWeak<'a, T> { | |
self.inc_weak(); | |
NoCycleWeak { _ptr: self._ptr, _marker: PhantomData } | |
} | |
} | |
impl<'a, T: fmt::Debug> fmt::Debug for NoCycleWeak<'a, T> { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
write!(f, "(Weak)") | |
} | |
} | |
/// Marker used to prevent cycles. | |
/// | |
/// NoCycleMarker is guaranteed to be outlived by all data in the NoCycleRc's | |
/// created with it, and will itself outlive the created NoCycleRc's. This | |
/// makes it impossible to create any cycles. | |
#[derive(Clone)] | |
pub struct NoCycleMarker<'a> { | |
marker: PhantomData<Cell<&'a ()>>, // 'a is invariant | |
} | |
impl<'a> NoCycleMarker<'a> { | |
pub fn new() -> NoCycleMarker<'a> { | |
NoCycleMarker { | |
marker: PhantomData, | |
} | |
} | |
pub fn new_rc<'b, T: 'a>(&'b self, val: T) -> NoCycleRc<'b, T> { | |
NoCycleRc::priv_new(val) | |
} | |
} | |
impl<'a> Drop for NoCycleMarker<'a> { | |
fn drop(&mut self) {} | |
} | |
#[doc(hidden)] | |
trait RcBoxPtr<T> { | |
fn inner(&self) -> &RcBox<T>; | |
#[inline] | |
fn strong(&self) -> usize { self.inner().strong.get() } | |
#[inline] | |
fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); } | |
#[inline] | |
fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); } | |
#[inline] | |
fn weak(&self) -> usize { self.inner().weak.get() } | |
#[inline] | |
fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); } | |
#[inline] | |
fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } | |
} | |
impl<'a, T> RcBoxPtr<T> for NoCycleRc<'a, T> { | |
#[inline(always)] | |
fn inner(&self) -> &RcBox<T> { | |
unsafe { | |
&(*self._ptr) | |
} | |
} | |
} | |
impl<'a, T> RcBoxPtr<T> for NoCycleWeak<'a, T> { | |
#[inline(always)] | |
fn inner(&self) -> &RcBox<T> { | |
unsafe { | |
&(*self._ptr) | |
} | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::{Rc, Weak, weak_count, strong_count}; | |
use std::boxed::Box; | |
use std::cell::RefCell; | |
use std::option::Option; | |
use std::option::Option::{Some, None}; | |
use std::result::Result::{Err, Ok}; | |
use std::mem::drop; | |
use std::clone::Clone; | |
#[test] | |
fn test_clone() { | |
let x = Rc::new(RefCell::new(5)); | |
let y = x.clone(); | |
*x.borrow_mut() = 20; | |
assert_eq!(*y.borrow(), 20); | |
} | |
#[test] | |
fn test_simple() { | |
let x = Rc::new(5); | |
assert_eq!(*x, 5); | |
} | |
#[test] | |
fn test_simple_clone() { | |
let x = Rc::new(5); | |
let y = x.clone(); | |
assert_eq!(*x, 5); | |
assert_eq!(*y, 5); | |
} | |
#[test] | |
fn test_destructor() { | |
let x: Rc<Box<_>> = Rc::new(box 5); | |
assert_eq!(**x, 5); | |
} | |
#[test] | |
fn test_live() { | |
let x = Rc::new(5); | |
let y = x.downgrade(); | |
assert!(y.upgrade().is_some()); | |
} | |
#[test] | |
fn test_dead() { | |
let x = Rc::new(5); | |
let y = x.downgrade(); | |
drop(x); | |
assert!(y.upgrade().is_none()); | |
} | |
#[test] | |
fn weak_self_cyclic() { | |
struct Cycle { | |
x: RefCell<Option<Weak<Cycle>>> | |
} | |
let a = Rc::new(Cycle { x: RefCell::new(None) }); | |
let b = a.clone().downgrade(); | |
*a.x.borrow_mut() = Some(b); | |
// hopefully we don't double-free (or leak)... | |
} | |
#[test] | |
fn is_unique() { | |
let x = Rc::new(3); | |
assert!(super::is_unique(&x)); | |
let y = x.clone(); | |
assert!(!super::is_unique(&x)); | |
drop(y); | |
assert!(super::is_unique(&x)); | |
let w = x.downgrade(); | |
assert!(!super::is_unique(&x)); | |
drop(w); | |
assert!(super::is_unique(&x)); | |
} | |
#[test] | |
fn test_strong_count() { | |
let a = Rc::new(0u32); | |
assert!(strong_count(&a) == 1); | |
let w = a.downgrade(); | |
assert!(strong_count(&a) == 1); | |
let b = w.upgrade().expect("upgrade of live rc failed"); | |
assert!(strong_count(&b) == 2); | |
assert!(strong_count(&a) == 2); | |
drop(w); | |
drop(a); | |
assert!(strong_count(&b) == 1); | |
let c = b.clone(); | |
assert!(strong_count(&b) == 2); | |
assert!(strong_count(&c) == 2); | |
} | |
#[test] | |
fn test_weak_count() { | |
let a = Rc::new(0u32); | |
assert!(strong_count(&a) == 1); | |
assert!(weak_count(&a) == 0); | |
let w = a.downgrade(); | |
assert!(strong_count(&a) == 1); | |
assert!(weak_count(&a) == 1); | |
drop(w); | |
assert!(strong_count(&a) == 1); | |
assert!(weak_count(&a) == 0); | |
let c = a.clone(); | |
assert!(strong_count(&a) == 2); | |
assert!(weak_count(&a) == 0); | |
drop(c); | |
} | |
#[test] | |
fn try_unwrap() { | |
let x = Rc::new(3); | |
assert_eq!(super::try_unwrap(x), Ok(3)); | |
let x = Rc::new(4); | |
let _y = x.clone(); | |
assert_eq!(super::try_unwrap(x), Err(Rc::new(4))); | |
let x = Rc::new(5); | |
let _w = x.downgrade(); | |
assert_eq!(super::try_unwrap(x), Err(Rc::new(5))); | |
} | |
#[test] | |
fn get_mut() { | |
let mut x = Rc::new(3); | |
*super::get_mut(&mut x).unwrap() = 4; | |
assert_eq!(*x, 4); | |
let y = x.clone(); | |
assert!(super::get_mut(&mut x).is_none()); | |
drop(y); | |
assert!(super::get_mut(&mut x).is_some()); | |
let _w = x.downgrade(); | |
assert!(super::get_mut(&mut x).is_none()); | |
} | |
#[test] | |
fn test_cowrc_clone_make_unique() { | |
let mut cow0 = Rc::new(75); | |
let mut cow1 = cow0.clone(); | |
let mut cow2 = cow1.clone(); | |
assert!(75 == *cow0.make_unique()); | |
assert!(75 == *cow1.make_unique()); | |
assert!(75 == *cow2.make_unique()); | |
*cow0.make_unique() += 1; | |
*cow1.make_unique() += 2; | |
*cow2.make_unique() += 3; | |
assert!(76 == *cow0); | |
assert!(77 == *cow1); | |
assert!(78 == *cow2); | |
// none should point to the same backing memory | |
assert!(*cow0 != *cow1); | |
assert!(*cow0 != *cow2); | |
assert!(*cow1 != *cow2); | |
} | |
#[test] | |
fn test_cowrc_clone_unique2() { | |
let mut cow0 = Rc::new(75); | |
let cow1 = cow0.clone(); | |
let cow2 = cow1.clone(); | |
assert!(75 == *cow0); | |
assert!(75 == *cow1); | |
assert!(75 == *cow2); | |
*cow0.make_unique() += 1; | |
assert!(76 == *cow0); | |
assert!(75 == *cow1); | |
assert!(75 == *cow2); | |
// cow1 and cow2 should share the same contents | |
// cow0 should have a unique reference | |
assert!(*cow0 != *cow1); | |
assert!(*cow0 != *cow2); | |
assert!(*cow1 == *cow2); | |
} | |
#[test] | |
fn test_cowrc_clone_weak() { | |
let mut cow0 = Rc::new(75); | |
let cow1_weak = cow0.downgrade(); | |
assert!(75 == *cow0); | |
assert!(75 == *cow1_weak.upgrade().unwrap()); | |
*cow0.make_unique() += 1; | |
assert!(76 == *cow0); | |
assert!(cow1_weak.upgrade().is_none()); | |
} | |
#[test] | |
fn test_show() { | |
let foo = Rc::new(75); | |
assert_eq!(format!("{:?}", foo), "75"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment