2013-05-04 18:51:05 -05: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-05-28 22:11:41 -05:00
|
|
|
#[allow(missing_doc)];
|
|
|
|
|
2013-05-04 18:51:05 -05:00
|
|
|
/** Task-local reference counted smart pointers
|
|
|
|
|
|
|
|
Task-local reference counted smart pointers are an alternative to managed boxes with deterministic
|
2013-06-05 19:56:24 -05:00
|
|
|
destruction. They are restricted to containing types that are either `Send` or `Freeze` (or both) to
|
2013-05-15 17:06:22 -05:00
|
|
|
prevent cycles.
|
|
|
|
|
2013-06-05 19:56:24 -05:00
|
|
|
Neither `Rc<T>` or `RcMut<T>` is ever `Send` and `RcMut<T>` is never `Freeze`. If `T` is `Freeze`, a
|
2013-05-15 17:06:22 -05:00
|
|
|
cycle cannot be created with `Rc<T>` because there is no way to modify it after creation.
|
2013-05-04 18:51:05 -05:00
|
|
|
|
|
|
|
*/
|
|
|
|
|
2013-05-17 17:28:44 -05:00
|
|
|
use core::prelude::*;
|
|
|
|
|
2013-05-24 21:35:29 -05:00
|
|
|
use core::cast;
|
2013-05-04 18:51:05 -05:00
|
|
|
use core::libc::{c_void, size_t, malloc, free};
|
2013-05-24 21:35:29 -05:00
|
|
|
use core::ptr;
|
|
|
|
use core::sys;
|
2013-05-04 18:51:05 -05:00
|
|
|
use core::unstable::intrinsics;
|
|
|
|
|
|
|
|
struct RcBox<T> {
|
|
|
|
value: T,
|
|
|
|
count: uint
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Immutable reference counted pointer type
|
2013-06-27 15:45:09 -05:00
|
|
|
#[unsafe_no_drop_flag]
|
2013-06-05 13:33:14 -05:00
|
|
|
#[non_sendable]
|
2013-05-04 18:51:05 -05:00
|
|
|
pub struct Rc<T> {
|
|
|
|
priv ptr: *mut RcBox<T>,
|
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
impl<T> Rc<T> {
|
2013-05-15 17:06:22 -05:00
|
|
|
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}
|
2013-05-04 18:51:05 -05:00
|
|
|
}
|
2013-05-15 17:06:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: #6516: should be a static method
|
2013-06-05 19:56:24 -05:00
|
|
|
pub fn rc_from_owned<T: Send>(value: T) -> Rc<T> {
|
2013-05-15 17:06:22 -05:00
|
|
|
unsafe { Rc::new(value) }
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: #6516: should be a static method
|
2013-06-05 17:53:17 -05:00
|
|
|
pub fn rc_from_const<T: Freeze>(value: T) -> Rc<T> {
|
2013-05-15 17:06:22 -05:00
|
|
|
unsafe { Rc::new(value) }
|
|
|
|
}
|
2013-05-04 18:51:05 -05:00
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
impl<T> Rc<T> {
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn borrow<'r>(&'r self) -> &'r T {
|
2013-05-08 14:03:39 -05:00
|
|
|
unsafe { cast::copy_lifetime(self, &(*self.ptr).value) }
|
2013-05-04 18:51:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[unsafe_destructor]
|
2013-05-15 17:06:22 -05:00
|
|
|
impl<T> Drop for Rc<T> {
|
2013-06-20 20:06:13 -05:00
|
|
|
fn drop(&self) {
|
2013-05-04 18:51:05 -05:00
|
|
|
unsafe {
|
2013-06-22 23:13:29 -05:00
|
|
|
if self.ptr.is_not_null() {
|
|
|
|
(*self.ptr).count -= 1;
|
|
|
|
if (*self.ptr).count == 0 {
|
|
|
|
ptr::replace_ptr(self.ptr, intrinsics::uninit());
|
|
|
|
free(self.ptr as *c_void)
|
|
|
|
}
|
2013-05-04 18:51:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-15 17:06:22 -05:00
|
|
|
impl<T> Clone for Rc<T> {
|
2013-05-14 23:45:40 -05:00
|
|
|
/// Return a shallow copy of the reference counted pointer.
|
2013-05-04 18:51:05 -05:00
|
|
|
#[inline]
|
|
|
|
fn clone(&self) -> Rc<T> {
|
|
|
|
unsafe {
|
|
|
|
(*self.ptr).count += 1;
|
2013-05-07 11:57:28 -05:00
|
|
|
Rc{ptr: self.ptr}
|
2013-05-04 18:51:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-15 17:06:22 -05:00
|
|
|
impl<T: DeepClone> DeepClone for Rc<T> {
|
2013-05-14 23:45:40 -05:00
|
|
|
/// Return a deep copy of the reference counted pointer.
|
|
|
|
#[inline]
|
|
|
|
fn deep_clone(&self) -> Rc<T> {
|
2013-05-15 17:06:22 -05:00
|
|
|
unsafe { Rc::new(self.borrow().deep_clone()) }
|
2013-05-14 23:45:40 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-04 18:51:05 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test_rc {
|
|
|
|
use super::*;
|
2013-05-14 23:45:40 -05:00
|
|
|
use core::cell::Cell;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_clone() {
|
2013-06-04 05:03:58 -05:00
|
|
|
let x = rc_from_owned(Cell::new(5));
|
2013-05-14 23:45:40 -05:00
|
|
|
let y = x.clone();
|
2013-05-15 01:23:12 -05:00
|
|
|
do x.borrow().with_mut_ref |inner| {
|
|
|
|
*inner = 20;
|
2013-05-14 23:45:40 -05:00
|
|
|
}
|
2013-05-15 01:23:12 -05:00
|
|
|
assert_eq!(y.borrow().take(), 20);
|
2013-05-14 23:45:40 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deep_clone() {
|
2013-06-04 05:03:58 -05:00
|
|
|
let x = rc_from_owned(Cell::new(5));
|
2013-05-14 23:45:40 -05:00
|
|
|
let y = x.deep_clone();
|
2013-05-15 01:23:12 -05:00
|
|
|
do x.borrow().with_mut_ref |inner| {
|
|
|
|
*inner = 20;
|
2013-05-14 23:45:40 -05:00
|
|
|
}
|
2013-05-15 01:23:12 -05:00
|
|
|
assert_eq!(y.borrow().take(), 5);
|
2013-05-14 23:45:40 -05:00
|
|
|
}
|
2013-05-04 18:51:05 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_simple() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_from_const(5);
|
2013-05-04 18:51:05 -05:00
|
|
|
assert_eq!(*x.borrow(), 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-05-15 01:23:12 -05:00
|
|
|
fn test_simple_clone() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_from_const(5);
|
2013-05-04 18:51:05 -05:00
|
|
|
let y = x.clone();
|
|
|
|
assert_eq!(*x.borrow(), 5);
|
|
|
|
assert_eq!(*y.borrow(), 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_destructor() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_from_owned(~5);
|
2013-05-04 18:51:05 -05:00
|
|
|
assert_eq!(**x.borrow(), 5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-09 16:14:42 -05:00
|
|
|
#[abi = "rust-intrinsic"]
|
|
|
|
extern "rust-intrinsic" {
|
|
|
|
fn init<T>() -> T;
|
|
|
|
fn uninit<T>() -> T;
|
|
|
|
}
|
|
|
|
|
2013-05-04 18:51:05 -05:00
|
|
|
#[deriving(Eq)]
|
|
|
|
enum Borrow {
|
|
|
|
Mutable,
|
|
|
|
Immutable,
|
|
|
|
Nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
struct RcMutBox<T> {
|
|
|
|
value: T,
|
|
|
|
count: uint,
|
|
|
|
borrow: Borrow
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Mutable reference counted pointer type
|
2013-05-07 11:57:28 -05:00
|
|
|
#[non_owned]
|
2013-06-05 13:33:14 -05:00
|
|
|
#[non_sendable]
|
2013-05-07 11:57:28 -05:00
|
|
|
#[mutable]
|
2013-06-27 15:45:09 -05:00
|
|
|
#[unsafe_no_drop_flag]
|
2013-05-04 18:51:05 -05:00
|
|
|
pub struct RcMut<T> {
|
|
|
|
priv ptr: *mut RcMutBox<T>,
|
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
impl<T> RcMut<T> {
|
2013-05-15 17:06:22 -05:00
|
|
|
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}
|
2013-05-04 18:51:05 -05:00
|
|
|
}
|
2013-05-15 17:06:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: #6516: should be a static method
|
2013-06-05 19:56:24 -05:00
|
|
|
pub fn rc_mut_from_owned<T: Send>(value: T) -> RcMut<T> {
|
2013-05-15 17:06:22 -05:00
|
|
|
unsafe { RcMut::new(value) }
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: #6516: should be a static method
|
2013-06-05 17:53:17 -05:00
|
|
|
pub fn rc_mut_from_const<T: Freeze>(value: T) -> RcMut<T> {
|
2013-05-15 17:06:22 -05:00
|
|
|
unsafe { RcMut::new(value) }
|
|
|
|
}
|
2013-05-04 18:51:05 -05:00
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
impl<T> RcMut<T> {
|
2013-05-04 18:51:05 -05:00
|
|
|
/// Fails if there is already a mutable borrow of the box
|
|
|
|
#[inline]
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn with_borrow<U>(&self, f: &fn(&T) -> U) -> U {
|
2013-05-04 18:51:05 -05:00
|
|
|
unsafe {
|
|
|
|
assert!((*self.ptr).borrow != Mutable);
|
|
|
|
let previous = (*self.ptr).borrow;
|
|
|
|
(*self.ptr).borrow = Immutable;
|
2013-05-14 23:45:40 -05:00
|
|
|
let res = f(&(*self.ptr).value);
|
2013-05-04 18:51:05 -05:00
|
|
|
(*self.ptr).borrow = previous;
|
2013-05-14 23:45:40 -05:00
|
|
|
res
|
2013-05-04 18:51:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Fails if there is already a mutable or immutable borrow of the box
|
|
|
|
#[inline]
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn with_mut_borrow<U>(&self, f: &fn(&mut T) -> U) -> U {
|
2013-05-04 18:51:05 -05:00
|
|
|
unsafe {
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!((*self.ptr).borrow, Nothing);
|
2013-05-04 18:51:05 -05:00
|
|
|
(*self.ptr).borrow = Mutable;
|
2013-05-14 23:45:40 -05:00
|
|
|
let res = f(&mut (*self.ptr).value);
|
2013-05-04 18:51:05 -05:00
|
|
|
(*self.ptr).borrow = Nothing;
|
2013-05-14 23:45:40 -05:00
|
|
|
res
|
2013-05-04 18:51:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[unsafe_destructor]
|
2013-05-15 17:06:22 -05:00
|
|
|
impl<T> Drop for RcMut<T> {
|
2013-06-20 20:06:13 -05:00
|
|
|
fn drop(&self) {
|
2013-05-04 18:51:05 -05:00
|
|
|
unsafe {
|
2013-06-22 23:13:29 -05:00
|
|
|
if self.ptr.is_not_null() {
|
|
|
|
(*self.ptr).count -= 1;
|
|
|
|
if (*self.ptr).count == 0 {
|
|
|
|
ptr::replace_ptr(self.ptr, uninit());
|
|
|
|
free(self.ptr as *c_void)
|
|
|
|
}
|
2013-05-09 06:05:17 -05:00
|
|
|
}
|
|
|
|
}
|
2013-05-04 18:51:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-15 17:06:22 -05:00
|
|
|
impl<T> Clone for RcMut<T> {
|
2013-05-14 23:45:40 -05:00
|
|
|
/// Return a shallow copy of the reference counted pointer.
|
2013-05-04 18:51:05 -05:00
|
|
|
#[inline]
|
|
|
|
fn clone(&self) -> RcMut<T> {
|
|
|
|
unsafe {
|
|
|
|
(*self.ptr).count += 1;
|
2013-05-07 11:57:28 -05:00
|
|
|
RcMut{ptr: self.ptr}
|
2013-05-04 18:51:05 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-15 17:06:22 -05:00
|
|
|
impl<T: DeepClone> DeepClone for RcMut<T> {
|
2013-05-14 23:45:40 -05:00
|
|
|
/// 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)
|
2013-05-15 17:06:22 -05:00
|
|
|
unsafe { RcMut::new(x.deep_clone()) }
|
2013-05-14 23:45:40 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-04 18:51:05 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test_rc_mut {
|
|
|
|
use super::*;
|
|
|
|
|
2013-05-14 23:45:40 -05:00
|
|
|
#[test]
|
|
|
|
fn test_clone() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_mut_from_owned(5);
|
2013-05-14 23:45:40 -05:00
|
|
|
let y = x.clone();
|
|
|
|
do x.with_mut_borrow |value| {
|
|
|
|
*value = 20;
|
|
|
|
}
|
|
|
|
do y.with_borrow |value| {
|
|
|
|
assert_eq!(*value, 20);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deep_clone() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_mut_from_const(5);
|
2013-05-14 23:45:40 -05:00
|
|
|
let y = x.deep_clone();
|
|
|
|
do x.with_mut_borrow |value| {
|
|
|
|
*value = 20;
|
|
|
|
}
|
|
|
|
do y.with_borrow |value| {
|
|
|
|
assert_eq!(*value, 5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-04 18:51:05 -05:00
|
|
|
#[test]
|
|
|
|
fn borrow_many() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_mut_from_owned(5);
|
2013-05-04 18:51:05 -05:00
|
|
|
let y = x.clone();
|
|
|
|
|
|
|
|
do x.with_borrow |a| {
|
|
|
|
assert_eq!(*a, 5);
|
|
|
|
do y.with_borrow |b| {
|
|
|
|
assert_eq!(*b, 5);
|
|
|
|
do x.with_borrow |c| {
|
|
|
|
assert_eq!(*c, 5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn modify() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_mut_from_const(5);
|
2013-05-04 18:51:05 -05:00
|
|
|
let y = x.clone();
|
|
|
|
|
|
|
|
do y.with_mut_borrow |a| {
|
|
|
|
assert_eq!(*a, 5);
|
|
|
|
*a = 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
do x.with_borrow |a| {
|
|
|
|
assert_eq!(*a, 6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn release_immutable() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_mut_from_owned(5);
|
2013-05-04 18:51:05 -05:00
|
|
|
do x.with_borrow |_| {}
|
|
|
|
do x.with_mut_borrow |_| {}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn release_mutable() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_mut_from_const(5);
|
2013-05-04 18:51:05 -05:00
|
|
|
do x.with_mut_borrow |_| {}
|
|
|
|
do x.with_borrow |_| {}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
|
|
|
fn frozen() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_mut_from_owned(5);
|
2013-05-04 18:51:05 -05:00
|
|
|
let y = x.clone();
|
|
|
|
|
|
|
|
do x.with_borrow |_| {
|
|
|
|
do y.with_mut_borrow |_| {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
|
|
|
fn mutable_dupe() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_mut_from_const(5);
|
2013-05-04 18:51:05 -05:00
|
|
|
let y = x.clone();
|
|
|
|
|
|
|
|
do x.with_mut_borrow |_| {
|
|
|
|
do y.with_mut_borrow |_| {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
|
|
|
fn mutable_freeze() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_mut_from_owned(5);
|
2013-05-04 18:51:05 -05:00
|
|
|
let y = x.clone();
|
|
|
|
|
|
|
|
do x.with_mut_borrow |_| {
|
|
|
|
do y.with_borrow |_| {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
|
|
|
fn restore_freeze() {
|
2013-05-15 17:06:22 -05:00
|
|
|
let x = rc_mut_from_const(5);
|
2013-05-04 18:51:05 -05:00
|
|
|
let y = x.clone();
|
|
|
|
|
|
|
|
do x.with_borrow |_| {
|
|
|
|
do x.with_borrow |_| {}
|
|
|
|
do y.with_mut_borrow |_| {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|