Skip to content

relax Rc restrictions and add strong/weak reference counted pointer type #10926

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

Merged
merged 4 commits into from
Jan 10, 2014
Merged
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions src/libextra/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,14 +406,14 @@ impl<S:Encoder,T:Encodable<S>> Encodable<S> for @T {
}
}

impl<S:Encoder,T:Encodable<S> + Freeze> Encodable<S> for Rc<T> {
impl<S:Encoder,T:Encodable<S>> Encodable<S> for Rc<T> {
#[inline]
fn encode(&self, s: &mut S) {
self.borrow().encode(s)
}
}

impl<D:Decoder,T:Decodable<D> + Freeze> Decodable<D> for Rc<T> {
impl<D:Decoder,T:Decodable<D>> Decodable<D> for Rc<T> {
#[inline]
fn decode(d: &mut D) -> Rc<T> {
Rc::new(Decodable::decode(d))
Expand Down
2 changes: 1 addition & 1 deletion src/librustuv/idle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) };
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
203 changes: 107 additions & 96 deletions src/libstd/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> {
value: T,
count: uint
strong: uint,
weak: uint
}

/// Immutable reference counted pointer type
Expand All @@ -36,147 +44,141 @@ pub struct Rc<T> {
priv ptr: *mut RcBox<T>
}

impl<T: Freeze> Rc<T> {
/// Construct a new reference-counted box from a `Freeze` value
#[inline]
impl<T> Rc<T> {
/// Construct a new reference-counted box
pub fn new(value: T) -> Rc<T> {
unsafe {
Rc::new_unchecked(value)
Rc { ptr: transmute(~RcBox { value: value, strong: 1, weak: 0 }) }
}
}
}

impl<T: Send> Rc<T> {
/// Construct a new reference-counted box from a `Send` value
#[inline]
pub fn from_send(value: T) -> Rc<T> {
impl<T> Rc<T> {
/// 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<T> {
unsafe {
Rc::new_unchecked(value)
(*self.ptr).weak += 1;
Weak { ptr: self.ptr }
}
}
}

impl<T: Freeze> Rc<RefCell<T>> {
/// Construct a new reference-counted box from a `RefCell`-wrapped `Freeze` value
#[inline]
pub fn from_mut(value: RefCell<T>) -> Rc<RefCell<T>> {
#[unsafe_destructor]
impl<T> Drop for Rc<T> {
fn drop(&mut self) {
unsafe {
Rc::new_unchecked(value)
if self.ptr != 0 as *mut RcBox<T> {
(*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<T> Rc<T> {
/// 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<T> {
Rc{ptr: transmute(~RcBox{value: value, count: 1})}
}

/// Borrow the value contained in the reference-counted box
impl<T> Clone for Rc<T> {
#[inline]
pub fn borrow<'r>(&'r self) -> &'r T {
unsafe { &(*self.ptr).value }
fn clone(&self) -> Rc<T> {
unsafe {
(*self.ptr).strong += 1;
Rc { ptr: self.ptr }
}
}
}

/// Determine if two reference-counted pointers point to the same object
impl<T: DeepClone> DeepClone for Rc<T> {
#[inline]
pub fn ptr_eq(&self, other: &Rc<T>) -> bool {
self.ptr == other.ptr
fn deep_clone(&self) -> Rc<T> {
Rc::new(self.borrow().deep_clone())
}
}

impl<T: Eq> Eq for Rc<T> {
#[inline]
fn eq(&self, other: &Rc<T>) -> bool {
unsafe { (*self.ptr).value == (*other.ptr).value }
}
#[inline(always)]
fn eq(&self, other: &Rc<T>) -> bool { *self.borrow() == *other.borrow() }

#[inline]
fn ne(&self, other: &Rc<T>) -> bool {
unsafe { (*self.ptr).value != (*other.ptr).value }
}
}

impl<T: TotalEq> TotalEq for Rc<T> {
#[inline]
fn equals(&self, other: &Rc<T>) -> bool {
unsafe { (*self.ptr).value.equals(&(*other.ptr).value) }
}
#[inline(always)]
fn ne(&self, other: &Rc<T>) -> bool { *self.borrow() != *other.borrow() }
}

impl<T: Ord> Ord for Rc<T> {
#[inline]
fn lt(&self, other: &Rc<T>) -> bool {
unsafe { (*self.ptr).value < (*other.ptr).value }
}
#[inline(always)]
fn lt(&self, other: &Rc<T>) -> bool { *self.borrow() < *other.borrow() }

#[inline]
fn le(&self, other: &Rc<T>) -> bool {
unsafe { (*self.ptr).value <= (*other.ptr).value }
}
#[inline(always)]
fn le(&self, other: &Rc<T>) -> bool { *self.borrow() <= *other.borrow() }

#[inline]
fn ge(&self, other: &Rc<T>) -> bool {
unsafe { (*self.ptr).value >= (*other.ptr).value }
}
#[inline(always)]
fn gt(&self, other: &Rc<T>) -> bool { *self.borrow() > *other.borrow() }

#[inline]
fn gt(&self, other: &Rc<T>) -> bool {
unsafe { (*self.ptr).value > (*other.ptr).value }
}
#[inline(always)]
fn ge(&self, other: &Rc<T>) -> bool { *self.borrow() >= *other.borrow() }
}

impl<T: TotalOrd> TotalOrd for Rc<T> {
#[inline]
fn cmp(&self, other: &Rc<T>) -> 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<T> {
priv ptr: *mut RcBox<T>
}

impl<T> Clone for Rc<T> {
#[inline]
fn clone(&self) -> Rc<T> {
impl<T> Weak<T> {
/// Upgrade a weak reference to a strong reference
pub fn upgrade(&self) -> Option<Rc<T>> {
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<T: DeepClone> DeepClone for Rc<T> {
#[inline]
fn deep_clone(&self) -> Rc<T> {
unsafe { Rc::new_unchecked(self.borrow().deep_clone()) }
}
}

#[unsafe_destructor]
impl<T> Drop for Rc<T> {
impl<T> Drop for Weak<T> {
fn drop(&mut self) {
unsafe {
if self.ptr.is_not_null() {
(*self.ptr).count -= 1;
if (*self.ptr).count == 0 {
let _: ~RcBox<T> = transmute(self.ptr);
if self.ptr != 0 as *mut RcBox<T> {
(*self.ptr).weak -= 1;
if (*self.ptr).weak == 0 && (*self.ptr).strong == 0 {
exchange_free(self.ptr as *mut u8 as *i8)
}
}
}
}
}

impl<T> Clone for Weak<T> {
#[inline]
fn clone(&self) -> Weak<T> {
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;
Expand All @@ -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;
Expand All @@ -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());
}
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-7013.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/no_freeze-rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ use std::cell::RefCell;
fn bar<T: Freeze>(_: 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<std::cell::RefCell<int>>`, which does not fulfill `Freeze`
}
21 changes: 0 additions & 21 deletions src/test/compile-fail/rcmut-not-const-and-not-owned.rs

This file was deleted.