2013-05-04 23:51:05 +00:00
|
|
|
// 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 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2013-12-24 16:08:28 +00:00
|
|
|
/*! Task-local reference-counted boxes (`Rc` type)
|
2013-05-29 03:11:41 +00:00
|
|
|
|
2013-10-10 15:45:52 +00:00
|
|
|
The `Rc` type provides shared ownership of an immutable value. Destruction is deterministic, and
|
|
|
|
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.
|
2013-05-04 23:51:05 +00:00
|
|
|
|
|
|
|
*/
|
|
|
|
|
2013-10-10 15:45:52 +00:00
|
|
|
use ptr::RawPtr;
|
|
|
|
use unstable::intrinsics::transmute;
|
|
|
|
use ops::Drop;
|
2013-12-11 23:03:25 +00:00
|
|
|
use kinds::NonManaged;
|
2013-10-10 15:45:52 +00:00
|
|
|
use clone::{Clone, DeepClone};
|
2013-11-24 16:29:44 +00:00
|
|
|
use cmp::{Eq, TotalEq, Ord, TotalOrd, Ordering};
|
2013-07-24 12:11:49 +00:00
|
|
|
|
2013-05-04 23:51:05 +00:00
|
|
|
struct RcBox<T> {
|
|
|
|
value: T,
|
|
|
|
count: uint
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Immutable reference counted pointer type
|
2013-06-27 20:45:09 +00:00
|
|
|
#[unsafe_no_drop_flag]
|
2013-06-28 21:33:58 +00:00
|
|
|
#[no_send]
|
2013-05-04 23:51:05 +00:00
|
|
|
pub struct Rc<T> {
|
2013-10-10 15:45:52 +00:00
|
|
|
priv ptr: *mut RcBox<T>
|
2013-05-15 22:06:22 +00:00
|
|
|
}
|
|
|
|
|
2013-12-11 23:03:25 +00:00
|
|
|
impl<T: NonManaged> Rc<T> {
|
|
|
|
/// Construct a new reference-counted box
|
2013-10-10 15:45:52 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn new(value: T) -> Rc<T> {
|
|
|
|
unsafe {
|
2013-12-11 23:03:25 +00:00
|
|
|
Rc { ptr: transmute(~RcBox { value: value, count: 1 }) }
|
2013-11-17 05:59:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 22:17:22 +00:00
|
|
|
impl<T> Rc<T> {
|
2013-10-10 15:45:52 +00:00
|
|
|
/// Borrow the value contained in the reference-counted box
|
|
|
|
#[inline]
|
|
|
|
pub fn borrow<'r>(&'r self) -> &'r T {
|
|
|
|
unsafe { &(*self.ptr).value }
|
2013-05-04 23:51:05 +00:00
|
|
|
}
|
2013-11-24 16:29:44 +00:00
|
|
|
|
|
|
|
/// Determine if two reference-counted pointers point to the same object
|
|
|
|
#[inline]
|
|
|
|
pub fn ptr_eq(&self, other: &Rc<T>) -> bool {
|
|
|
|
self.ptr == other.ptr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Eq> Eq for Rc<T> {
|
|
|
|
#[inline]
|
|
|
|
fn eq(&self, other: &Rc<T>) -> bool {
|
|
|
|
unsafe { (*self.ptr).value == (*other.ptr).value }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Ord> Ord for Rc<T> {
|
|
|
|
#[inline]
|
|
|
|
fn lt(&self, other: &Rc<T>) -> bool {
|
|
|
|
unsafe { (*self.ptr).value < (*other.ptr).value }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn le(&self, other: &Rc<T>) -> bool {
|
|
|
|
unsafe { (*self.ptr).value <= (*other.ptr).value }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn ge(&self, other: &Rc<T>) -> bool {
|
|
|
|
unsafe { (*self.ptr).value >= (*other.ptr).value }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn gt(&self, other: &Rc<T>) -> bool {
|
|
|
|
unsafe { (*self.ptr).value > (*other.ptr).value }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: TotalOrd> TotalOrd for Rc<T> {
|
|
|
|
#[inline]
|
|
|
|
fn cmp(&self, other: &Rc<T>) -> Ordering {
|
|
|
|
unsafe { (*self.ptr).value.cmp(&(*other.ptr).value) }
|
|
|
|
}
|
2013-05-04 23:51:05 +00:00
|
|
|
}
|
|
|
|
|
2013-05-15 22:06:22 +00:00
|
|
|
impl<T> Clone for Rc<T> {
|
2013-05-04 23:51:05 +00:00
|
|
|
#[inline]
|
|
|
|
fn clone(&self) -> Rc<T> {
|
|
|
|
unsafe {
|
|
|
|
(*self.ptr).count += 1;
|
2013-05-07 16:57:28 +00:00
|
|
|
Rc{ptr: self.ptr}
|
2013-05-04 23:51:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-11 23:03:25 +00:00
|
|
|
impl<T: NonManaged + DeepClone> DeepClone for Rc<T> {
|
2013-05-15 04:45:40 +00:00
|
|
|
#[inline]
|
|
|
|
fn deep_clone(&self) -> Rc<T> {
|
2013-12-11 23:03:25 +00:00
|
|
|
Rc::new(self.borrow().deep_clone())
|
2013-10-10 15:45:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[unsafe_destructor]
|
|
|
|
impl<T> Drop for Rc<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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-05-15 04:45:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-04 23:51:05 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test_rc {
|
2014-01-07 06:33:37 +00:00
|
|
|
use prelude::*;
|
2013-05-04 23:51:05 +00:00
|
|
|
use super::*;
|
2013-11-22 05:30:34 +00:00
|
|
|
use cell::RefCell;
|
2013-05-15 04:45:40 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_clone() {
|
2013-12-11 23:03:25 +00:00
|
|
|
let x = Rc::new(RefCell::new(5));
|
2013-11-06 22:56:22 +00:00
|
|
|
let y = x.clone();
|
2013-11-20 22:17:12 +00:00
|
|
|
x.borrow().with_mut(|inner| {
|
2013-11-06 22:56:22 +00:00
|
|
|
*inner = 20;
|
2013-11-20 22:17:12 +00:00
|
|
|
});
|
2013-11-16 19:19:25 +00:00
|
|
|
assert_eq!(y.borrow().with(|v| *v), 20);
|
2013-05-15 04:45:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deep_clone() {
|
2013-12-11 23:03:25 +00:00
|
|
|
let x = Rc::new(RefCell::new(5));
|
2013-11-06 22:56:22 +00:00
|
|
|
let y = x.deep_clone();
|
2013-11-20 22:17:12 +00:00
|
|
|
x.borrow().with_mut(|inner| {
|
2013-11-06 22:56:22 +00:00
|
|
|
*inner = 20;
|
2013-11-20 22:17:12 +00:00
|
|
|
});
|
2013-11-16 19:19:25 +00:00
|
|
|
assert_eq!(y.borrow().with(|v| *v), 5);
|
2013-05-15 04:45:40 +00:00
|
|
|
}
|
2013-05-04 23:51:05 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_simple() {
|
2013-10-10 15:45:52 +00:00
|
|
|
let x = Rc::new(5);
|
2013-05-04 23:51:05 +00:00
|
|
|
assert_eq!(*x.borrow(), 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-05-15 06:23:12 +00:00
|
|
|
fn test_simple_clone() {
|
2013-10-10 15:45:52 +00:00
|
|
|
let x = Rc::new(5);
|
2013-05-04 23:51:05 +00:00
|
|
|
let y = x.clone();
|
|
|
|
assert_eq!(*x.borrow(), 5);
|
|
|
|
assert_eq!(*y.borrow(), 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_destructor() {
|
2013-12-11 23:03:25 +00:00
|
|
|
let x = Rc::new(~5);
|
2013-11-06 22:56:22 +00:00
|
|
|
assert_eq!(**x.borrow(), 5);
|
2013-05-04 23:51:05 +00:00
|
|
|
}
|
|
|
|
}
|