Skip to content

allow constructing Rc/RcMut from Const types too #6520

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 66 additions & 42 deletions src/libstd/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
/** Task-local reference counted smart pointers

Task-local reference counted smart pointers are an alternative to managed boxes with deterministic
destruction. They are restricted to containing `Owned` types in order to prevent cycles.
destruction. They are restricted to containing types that are either `Owned` or `Const` (or both) to
prevent cycles.

Neither `Rc<T>` or `RcMut<T>` is ever `Owned` and `RcMut<T>` is never `Const`. If `T` is `Const`, a
cycle cannot be created with `Rc<T>` because there is no way to modify it after creation.

*/

Expand All @@ -30,16 +34,26 @@ pub struct Rc<T> {
priv ptr: *mut RcBox<T>,
}

pub impl<T: Owned> Rc<T> {
fn new(value: T) -> Rc<T> {
unsafe {
let ptr = malloc(sys::size_of::<RcBox<T>>() as size_t) as *mut RcBox<T>;
assert!(!ptr::is_null(ptr));
intrinsics::move_val_init(&mut *ptr, RcBox{value: value, count: 1});
Rc{ptr: ptr}
}
priv impl<T> Rc<T> {
unsafe fn new(value: T) -> Rc<T> {
let ptr = malloc(sys::size_of::<RcBox<T>>() as size_t) as *mut RcBox<T>;
assert!(!ptr::is_null(ptr));
intrinsics::move_val_init(&mut *ptr, RcBox{value: value, count: 1});
Rc{ptr: ptr}
}
}

// FIXME: #6516: should be a static method
pub fn rc_from_owned<T: Owned>(value: T) -> Rc<T> {
unsafe { Rc::new(value) }
}

// FIXME: #6516: should be a static method
pub fn rc_from_const<T: Const>(value: T) -> Rc<T> {
unsafe { Rc::new(value) }
}

pub impl<T> Rc<T> {
#[inline(always)]
fn borrow<'r>(&'r self) -> &'r T {
unsafe { cast::copy_lifetime(self, &(*self.ptr).value) }
Expand All @@ -48,7 +62,7 @@ pub impl<T: Owned> Rc<T> {

#[unsafe_destructor]
#[cfg(not(stage0))]
impl<T: Owned> Drop for Rc<T> {
impl<T> Drop for Rc<T> {
fn finalize(&self) {
unsafe {
(*self.ptr).count -= 1;
Expand All @@ -62,7 +76,7 @@ impl<T: Owned> Drop for Rc<T> {

#[unsafe_destructor]
#[cfg(stage0)]
impl<T: Owned> Drop for Rc<T> {
impl<T> Drop for Rc<T> {
fn finalize(&self) {
unsafe {
(*self.ptr).count -= 1;
Expand All @@ -75,7 +89,7 @@ impl<T: Owned> Drop for Rc<T> {
}


impl<T: Owned> Clone for Rc<T> {
impl<T> Clone for Rc<T> {
/// Return a shallow copy of the reference counted pointer.
#[inline]
fn clone(&self) -> Rc<T> {
Expand All @@ -86,11 +100,11 @@ impl<T: Owned> Clone for Rc<T> {
}
}

impl<T: Owned + DeepClone> DeepClone for Rc<T> {
impl<T: DeepClone> DeepClone for Rc<T> {
/// Return a deep copy of the reference counted pointer.
#[inline]
fn deep_clone(&self) -> Rc<T> {
Rc::new(self.borrow().deep_clone())
unsafe { Rc::new(self.borrow().deep_clone()) }
}
}

Expand All @@ -101,7 +115,7 @@ mod test_rc {

#[test]
fn test_clone() {
let x = Rc::new(Cell(5));
let x = rc_from_owned(Cell(5));
let y = x.clone();
do x.borrow().with_mut_ref |inner| {
*inner = 20;
Expand All @@ -111,7 +125,7 @@ mod test_rc {

#[test]
fn test_deep_clone() {
let x = Rc::new(Cell(5));
let x = rc_from_owned(Cell(5));
let y = x.deep_clone();
do x.borrow().with_mut_ref |inner| {
*inner = 20;
Expand All @@ -121,21 +135,21 @@ mod test_rc {

#[test]
fn test_simple() {
let x = Rc::new(5);
let x = rc_from_const(5);
assert_eq!(*x.borrow(), 5);
}

#[test]
fn test_simple_clone() {
let x = Rc::new(5);
let x = rc_from_const(5);
let y = x.clone();
assert_eq!(*x.borrow(), 5);
assert_eq!(*y.borrow(), 5);
}

#[test]
fn test_destructor() {
let x = Rc::new(~5);
let x = rc_from_owned(~5);
assert_eq!(**x.borrow(), 5);
}
}
Expand Down Expand Up @@ -167,16 +181,26 @@ pub struct RcMut<T> {
priv ptr: *mut RcMutBox<T>,
}

pub impl<T: Owned> RcMut<T> {
fn new(value: T) -> RcMut<T> {
unsafe {
let ptr = malloc(sys::size_of::<RcMutBox<T>>() as size_t) as *mut RcMutBox<T>;
assert!(!ptr::is_null(ptr));
intrinsics::move_val_init(&mut *ptr, RcMutBox{value: value, count: 1, borrow: Nothing});
RcMut{ptr: ptr}
}
priv impl<T> RcMut<T> {
unsafe fn new(value: T) -> RcMut<T> {
let ptr = malloc(sys::size_of::<RcMutBox<T>>() as size_t) as *mut RcMutBox<T>;
assert!(!ptr::is_null(ptr));
intrinsics::move_val_init(&mut *ptr, RcMutBox{value: value, count: 1, borrow: Nothing});
RcMut{ptr: ptr}
}
}

// FIXME: #6516: should be a static method
pub fn rc_mut_from_owned<T: Owned>(value: T) -> RcMut<T> {
unsafe { RcMut::new(value) }
}

// FIXME: #6516: should be a static method
pub fn rc_mut_from_const<T: Const>(value: T) -> RcMut<T> {
unsafe { RcMut::new(value) }
}

pub impl<T> RcMut<T> {
/// Fails if there is already a mutable borrow of the box
#[inline]
fn with_borrow<U>(&self, f: &fn(&T) -> U) -> U {
Expand Down Expand Up @@ -205,7 +229,7 @@ pub impl<T: Owned> RcMut<T> {

#[unsafe_destructor]
#[cfg(not(stage0))]
impl<T: Owned> Drop for RcMut<T> {
impl<T> Drop for RcMut<T> {
fn finalize(&self) {
unsafe {
(*self.ptr).count -= 1;
Expand All @@ -219,7 +243,7 @@ impl<T: Owned> Drop for RcMut<T> {

#[unsafe_destructor]
#[cfg(stage0)]
impl<T: Owned> Drop for RcMut<T> {
impl<T> Drop for RcMut<T> {
fn finalize(&self) {
unsafe {
(*self.ptr).count -= 1;
Expand All @@ -231,7 +255,7 @@ impl<T: Owned> Drop for RcMut<T> {
}
}

impl<T: Owned> Clone for RcMut<T> {
impl<T> Clone for RcMut<T> {
/// Return a shallow copy of the reference counted pointer.
#[inline]
fn clone(&self) -> RcMut<T> {
Expand All @@ -242,13 +266,13 @@ impl<T: Owned> Clone for RcMut<T> {
}
}

impl<T: Owned + DeepClone> DeepClone for RcMut<T> {
impl<T: DeepClone> DeepClone for RcMut<T> {
/// Return a deep copy of the reference counted pointer.
#[inline]
fn deep_clone(&self) -> RcMut<T> {
do self.with_borrow |x| {
// FIXME: #6497: should avoid freeze (slow)
RcMut::new(x.deep_clone())
unsafe { RcMut::new(x.deep_clone()) }
}
}
}
Expand All @@ -259,7 +283,7 @@ mod test_rc_mut {

#[test]
fn test_clone() {
let x = RcMut::new(5);
let x = rc_mut_from_owned(5);
let y = x.clone();
do x.with_mut_borrow |value| {
*value = 20;
Expand All @@ -271,7 +295,7 @@ mod test_rc_mut {

#[test]
fn test_deep_clone() {
let x = RcMut::new(5);
let x = rc_mut_from_const(5);
let y = x.deep_clone();
do x.with_mut_borrow |value| {
*value = 20;
Expand All @@ -283,7 +307,7 @@ mod test_rc_mut {

#[test]
fn borrow_many() {
let x = RcMut::new(5);
let x = rc_mut_from_owned(5);
let y = x.clone();

do x.with_borrow |a| {
Expand All @@ -299,7 +323,7 @@ mod test_rc_mut {

#[test]
fn modify() {
let x = RcMut::new(5);
let x = rc_mut_from_const(5);
let y = x.clone();

do y.with_mut_borrow |a| {
Expand All @@ -314,22 +338,22 @@ mod test_rc_mut {

#[test]
fn release_immutable() {
let x = RcMut::new(5);
let x = rc_mut_from_owned(5);
do x.with_borrow |_| {}
do x.with_mut_borrow |_| {}
}

#[test]
fn release_mutable() {
let x = RcMut::new(5);
let x = rc_mut_from_const(5);
do x.with_mut_borrow |_| {}
do x.with_borrow |_| {}
}

#[test]
#[should_fail]
fn frozen() {
let x = RcMut::new(5);
let x = rc_mut_from_owned(5);
let y = x.clone();

do x.with_borrow |_| {
Expand All @@ -341,7 +365,7 @@ mod test_rc_mut {
#[test]
#[should_fail]
fn mutable_dupe() {
let x = RcMut::new(5);
let x = rc_mut_from_const(5);
let y = x.clone();

do x.with_mut_borrow |_| {
Expand All @@ -353,7 +377,7 @@ mod test_rc_mut {
#[test]
#[should_fail]
fn mutable_freeze() {
let x = RcMut::new(5);
let x = rc_mut_from_owned(5);
let y = x.clone();

do x.with_mut_borrow |_| {
Expand All @@ -365,7 +389,7 @@ mod test_rc_mut {
#[test]
#[should_fail]
fn restore_freeze() {
let x = RcMut::new(5);
let x = rc_mut_from_const(5);
let y = x.clone();

do x.with_borrow |_| {
Expand Down