diff --git a/src/libextra/serialize.rs b/src/libextra/serialize.rs index 59f7f2a2ffcb1..020404057fb1f 100644 --- a/src/libextra/serialize.rs +++ b/src/libextra/serialize.rs @@ -406,14 +406,14 @@ impl> Encodable for @T { } } -impl + Freeze> Encodable for Rc { +impl> Encodable for Rc { #[inline] fn encode(&self, s: &mut S) { self.borrow().encode(s) } } -impl + Freeze> Decodable for Rc { +impl> Decodable for Rc { #[inline] fn decode(d: &mut D) -> Rc { Rc::new(Decodable::decode(d)) diff --git a/src/librustuv/idle.rs b/src/librustuv/idle.rs index 80d21404e4bcb..3d6e81d0d6fd5 100644 --- a/src/librustuv/idle.rs +++ b/src/librustuv/idle.rs @@ -127,7 +127,7 @@ mod test { } fn mk(v: uint) -> (~IdleWatcher, Chan) { - let rc = Rc::from_send(RefCell::new((None, 0))); + let rc = Rc::new(RefCell::new((None, 0))); let cb = ~MyCallback(rc.clone(), v); let cb = cb as ~Callback:; let cb = unsafe { cast::transmute(cb) }; diff --git a/src/libstd/option.rs b/src/libstd/option.rs index f49244a3607ef..7ce9873c2da41 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -509,7 +509,7 @@ mod tests { } } - let i = Rc::from_send(RefCell::new(0)); + let i = Rc::new(RefCell::new(0)); { let x = R(i.clone()); let opt = Some(x); diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs index ad2305c241017..9947d8822ae65 100644 --- a/src/libstd/rc.rs +++ b/src/libstd/rc.rs @@ -14,19 +14,27 @@ The `Rc` type provides shared ownership of an immutable value. Destruction is de will occur as soon as the last owner is gone. It is marked as non-sendable because it avoids the overhead of atomic reference counting. +The `downgrade` method can be used to create a non-owning `Weak` pointer to the box. A `Weak` +pointer can be upgraded to an `Rc` pointer, but will return `None` if the value has already been +freed. + +For example, a tree with parent pointers can be represented by putting the nodes behind `Strong` +pointers, and then storing the parent pointers as `Weak` pointers. + */ -use ptr::RawPtr; -use unstable::intrinsics::transmute; +use cast::transmute; use ops::Drop; -use kinds::{Freeze, Send}; +use cmp::{Eq, Ord}; use clone::{Clone, DeepClone}; -use cell::RefCell; -use cmp::{Eq, TotalEq, Ord, TotalOrd, Ordering}; +use rt::global_heap::exchange_free; +use ptr::read_ptr; +use option::{Option, Some, None}; struct RcBox { value: T, - count: uint + strong: uint, + weak: uint } /// Immutable reference counted pointer type @@ -36,147 +44,141 @@ pub struct Rc { priv ptr: *mut RcBox } -impl Rc { - /// Construct a new reference-counted box from a `Freeze` value - #[inline] +impl Rc { + /// Construct a new reference-counted box pub fn new(value: T) -> Rc { unsafe { - Rc::new_unchecked(value) + Rc { ptr: transmute(~RcBox { value: value, strong: 1, weak: 0 }) } } } } -impl Rc { - /// Construct a new reference-counted box from a `Send` value - #[inline] - pub fn from_send(value: T) -> Rc { +impl Rc { + /// Borrow the value contained in the reference-counted box + #[inline(always)] + pub fn borrow<'a>(&'a self) -> &'a T { + unsafe { &(*self.ptr).value } + } + + /// Downgrade the reference-counted pointer to a weak reference + pub fn downgrade(&self) -> Weak { unsafe { - Rc::new_unchecked(value) + (*self.ptr).weak += 1; + Weak { ptr: self.ptr } } } } -impl Rc> { - /// Construct a new reference-counted box from a `RefCell`-wrapped `Freeze` value - #[inline] - pub fn from_mut(value: RefCell) -> Rc> { +#[unsafe_destructor] +impl Drop for Rc { + fn drop(&mut self) { unsafe { - Rc::new_unchecked(value) + if self.ptr != 0 as *mut RcBox { + (*self.ptr).strong -= 1; + if (*self.ptr).strong == 0 { + read_ptr(self.borrow()); // destroy the contained object + if (*self.ptr).weak == 0 { + exchange_free(self.ptr as *mut u8 as *i8) + } + } + } } } } -impl Rc { - /// Unsafety construct a new reference-counted box from any value. - /// - /// It is possible to create cycles, which will leak, and may interact - /// poorly with managed pointers. - #[inline] - pub unsafe fn new_unchecked(value: T) -> Rc { - Rc{ptr: transmute(~RcBox{value: value, count: 1})} - } - - /// Borrow the value contained in the reference-counted box +impl Clone for Rc { #[inline] - pub fn borrow<'r>(&'r self) -> &'r T { - unsafe { &(*self.ptr).value } + fn clone(&self) -> Rc { + unsafe { + (*self.ptr).strong += 1; + Rc { ptr: self.ptr } + } } +} - /// Determine if two reference-counted pointers point to the same object +impl DeepClone for Rc { #[inline] - pub fn ptr_eq(&self, other: &Rc) -> bool { - self.ptr == other.ptr + fn deep_clone(&self) -> Rc { + Rc::new(self.borrow().deep_clone()) } } impl Eq for Rc { - #[inline] - fn eq(&self, other: &Rc) -> bool { - unsafe { (*self.ptr).value == (*other.ptr).value } - } + #[inline(always)] + fn eq(&self, other: &Rc) -> bool { *self.borrow() == *other.borrow() } - #[inline] - fn ne(&self, other: &Rc) -> bool { - unsafe { (*self.ptr).value != (*other.ptr).value } - } -} - -impl TotalEq for Rc { - #[inline] - fn equals(&self, other: &Rc) -> bool { - unsafe { (*self.ptr).value.equals(&(*other.ptr).value) } - } + #[inline(always)] + fn ne(&self, other: &Rc) -> bool { *self.borrow() != *other.borrow() } } impl Ord for Rc { - #[inline] - fn lt(&self, other: &Rc) -> bool { - unsafe { (*self.ptr).value < (*other.ptr).value } - } + #[inline(always)] + fn lt(&self, other: &Rc) -> bool { *self.borrow() < *other.borrow() } - #[inline] - fn le(&self, other: &Rc) -> bool { - unsafe { (*self.ptr).value <= (*other.ptr).value } - } + #[inline(always)] + fn le(&self, other: &Rc) -> bool { *self.borrow() <= *other.borrow() } - #[inline] - fn ge(&self, other: &Rc) -> bool { - unsafe { (*self.ptr).value >= (*other.ptr).value } - } + #[inline(always)] + fn gt(&self, other: &Rc) -> bool { *self.borrow() > *other.borrow() } - #[inline] - fn gt(&self, other: &Rc) -> bool { - unsafe { (*self.ptr).value > (*other.ptr).value } - } + #[inline(always)] + fn ge(&self, other: &Rc) -> bool { *self.borrow() >= *other.borrow() } } -impl TotalOrd for Rc { - #[inline] - fn cmp(&self, other: &Rc) -> Ordering { - unsafe { (*self.ptr).value.cmp(&(*other.ptr).value) } - } +/// Weak reference to a reference-counted box +#[unsafe_no_drop_flag] +#[no_send] +pub struct Weak { + priv ptr: *mut RcBox } -impl Clone for Rc { - #[inline] - fn clone(&self) -> Rc { +impl Weak { + /// Upgrade a weak reference to a strong reference + pub fn upgrade(&self) -> Option> { unsafe { - (*self.ptr).count += 1; - Rc{ptr: self.ptr} + if (*self.ptr).strong == 0 { + None + } else { + (*self.ptr).strong += 1; + Some(Rc { ptr: self.ptr }) + } } } } -impl DeepClone for Rc { - #[inline] - fn deep_clone(&self) -> Rc { - unsafe { Rc::new_unchecked(self.borrow().deep_clone()) } - } -} - #[unsafe_destructor] -impl Drop for Rc { +impl Drop for Weak { fn drop(&mut self) { unsafe { - if self.ptr.is_not_null() { - (*self.ptr).count -= 1; - if (*self.ptr).count == 0 { - let _: ~RcBox = transmute(self.ptr); + if self.ptr != 0 as *mut RcBox { + (*self.ptr).weak -= 1; + if (*self.ptr).weak == 0 && (*self.ptr).strong == 0 { + exchange_free(self.ptr as *mut u8 as *i8) } } } } } +impl Clone for Weak { + #[inline] + fn clone(&self) -> Weak { + unsafe { + (*self.ptr).weak += 1; + Weak { ptr: self.ptr } + } + } +} + #[cfg(test)] -mod test_rc { +mod tests { use prelude::*; use super::*; use cell::RefCell; #[test] fn test_clone() { - let x = Rc::from_send(RefCell::new(5)); + let x = Rc::new(RefCell::new(5)); let y = x.clone(); x.borrow().with_mut(|inner| { *inner = 20; @@ -186,7 +188,7 @@ mod test_rc { #[test] fn test_deep_clone() { - let x = Rc::from_send(RefCell::new(5)); + let x = Rc::new(RefCell::new(5)); let y = x.deep_clone(); x.borrow().with_mut(|inner| { *inner = 20; @@ -210,13 +212,22 @@ mod test_rc { #[test] fn test_destructor() { - let x = Rc::from_send(~5); + let x = Rc::new(~5); assert_eq!(**x.borrow(), 5); } #[test] - fn test_from_mut() { - let a = 10; - let _x = Rc::from_mut(RefCell::new(&a)); + 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()); } } diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs index 9276a2f0d4194..cf7cb1a5a535f 100644 --- a/src/test/compile-fail/issue-7013.rs +++ b/src/test/compile-fail/issue-7013.rs @@ -37,7 +37,7 @@ struct A fn main() { let a = A {v: ~B{v: None} as ~Foo}; //~ ERROR cannot pack type `~B`, which does not fulfill `Send` - let v = Rc::from_send(RefCell::new(a)); + let v = Rc::new(RefCell::new(a)); let w = v.clone(); let b = v.borrow(); let mut b = b.borrow_mut(); diff --git a/src/test/compile-fail/no_freeze-rc.rs b/src/test/compile-fail/no_freeze-rc.rs index dbf5d0fb3f98b..a963446b84c73 100644 --- a/src/test/compile-fail/no_freeze-rc.rs +++ b/src/test/compile-fail/no_freeze-rc.rs @@ -14,6 +14,6 @@ use std::cell::RefCell; fn bar(_: T) {} fn main() { - let x = Rc::from_send(RefCell::new(5)); + let x = Rc::new(RefCell::new(5)); bar(x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::Rc>`, which does not fulfill `Freeze` } diff --git a/src/test/compile-fail/rcmut-not-const-and-not-owned.rs b/src/test/compile-fail/rcmut-not-const-and-not-owned.rs deleted file mode 100644 index 7e0c8319356e4..0000000000000 --- a/src/test/compile-fail/rcmut-not-const-and-not-owned.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::cell::RefCell; -use std::rc::Rc; - -fn o(_: &T) {} -fn c(_: &T) {} - -fn main() { - let x = Rc::from_send(RefCell::new(0)); - o(&x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::Rc>`, which does not fulfill `Send` - c(&x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::Rc>`, which does not fulfill `Freeze` -}