Skip to content

Instantly share code, notes, and snippets.

@rkjnsn
Created April 27, 2015 21:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rkjnsn/642766e1d81925e2540b to your computer and use it in GitHub Desktop.
Save rkjnsn/642766e1d81925e2540b to your computer and use it in GitHub Desktop.
Experiment with creating NoCycleRc
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