Skip to content

Commit c147ec6

Browse files
committed
auto merge of #9794 : thestinger/rust/rc, r=alexcrichton
I've left out a way to construct from a `Send` type until #9509 is resolved. I am confident that this interface can remain backwards compatible though, assuming we name the `Pointer` trait method `borrow`. When there is a way to convert from `Send` (`from_send`), a future RAII-based `Mut` type can be used with this to implemented a mutable reference-counted pointer. For now, I've left around the `RcMut` type but it may drastically change or be removed.
2 parents ed37b00 + 18be986 commit c147ec6

10 files changed

+114
-89
lines changed

src/libextra/extra.rs

-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ pub use std::os;
4646

4747
pub mod c_vec;
4848
pub mod io_util;
49-
pub mod rc;
5049

5150
// Concurrency
5251

src/libextra/rc.rs renamed to src/libstd/rc.rs

+89-81
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,23 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#[allow(missing_doc)];
11+
/** Task-local reference counted boxes
1212
13-
/** Task-local reference counted smart pointers
13+
The `Rc` type provides shared ownership of an immutable value. Destruction is deterministic, and
14+
will occur as soon as the last owner is gone. It is marked as non-sendable because it avoids the
15+
overhead of atomic reference counting.
1416
15-
Task-local reference counted smart pointers are an alternative to managed boxes with deterministic
16-
destruction. They are restricted to containing types that are either `Send` or `Freeze` (or both) to
17-
prevent cycles.
18-
19-
Neither `Rc<T>` or `RcMut<T>` is ever `Send` and `RcMut<T>` is never `Freeze`. If `T` is `Freeze`, a
20-
cycle cannot be created with `Rc<T>` because there is no way to modify it after creation.
17+
The `RcMut` type provides shared ownership of a mutable value. Since multiple owners prevent
18+
inherited mutability, a dynamic freezing check is used to maintain the invariant that an `&mut`
19+
reference is a unique handle and the type is marked as non-`Freeze`.
2120
2221
*/
2322

24-
25-
use std::cast;
26-
use std::ptr;
27-
use std::unstable::intrinsics;
28-
29-
// Convert ~T into *mut T without dropping it
30-
#[inline]
31-
unsafe fn owned_to_raw<T>(mut box: ~T) -> *mut T {
32-
let ptr = ptr::to_mut_unsafe_ptr(box);
33-
intrinsics::forget(box);
34-
ptr
35-
}
23+
use ptr::RawPtr;
24+
use unstable::intrinsics::transmute;
25+
use ops::Drop;
26+
use kinds::{Freeze, Send};
27+
use clone::{Clone, DeepClone};
3628

3729
struct RcBox<T> {
3830
value: T,
@@ -43,50 +35,38 @@ struct RcBox<T> {
4335
#[unsafe_no_drop_flag]
4436
#[no_send]
4537
pub struct Rc<T> {
46-
priv ptr: *mut RcBox<T>,
47-
}
48-
49-
impl<T> Rc<T> {
50-
unsafe fn new(value: T) -> Rc<T> {
51-
Rc{ptr: owned_to_raw(~RcBox{value: value, count: 1})}
52-
}
53-
}
54-
55-
impl<T: Send> Rc<T> {
56-
pub fn from_send(value: T) -> Rc<T> {
57-
unsafe { Rc::new(value) }
58-
}
38+
priv ptr: *mut RcBox<T>
5939
}
6040

6141
impl<T: Freeze> Rc<T> {
62-
pub fn from_freeze(value: T) -> Rc<T> {
63-
unsafe { Rc::new(value) }
42+
/// Construct a new reference-counted box from a `Freeze` value
43+
#[inline]
44+
pub fn new(value: T) -> Rc<T> {
45+
unsafe {
46+
Rc::new_unchecked(value)
47+
}
6448
}
6549
}
6650

6751
impl<T> Rc<T> {
52+
/// Unsafety construct a new reference-counted box from any value.
53+
///
54+
/// If the type is not `Freeze`, the `Rc` box will incorrectly still be considered as a `Freeze`
55+
/// type. It is also possible to create cycles, which will leak, and may interact poorly with
56+
/// managed pointers.
6857
#[inline]
69-
pub fn borrow<'r>(&'r self) -> &'r T {
70-
unsafe { cast::copy_lifetime(self, &(*self.ptr).value) }
58+
pub unsafe fn new_unchecked(value: T) -> Rc<T> {
59+
Rc{ptr: transmute(~RcBox{value: value, count: 1})}
7160
}
72-
}
7361

74-
#[unsafe_destructor]
75-
impl<T> Drop for Rc<T> {
76-
fn drop(&mut self) {
77-
unsafe {
78-
if self.ptr.is_not_null() {
79-
(*self.ptr).count -= 1;
80-
if (*self.ptr).count == 0 {
81-
let _: ~T = cast::transmute(self.ptr);
82-
}
83-
}
84-
}
62+
/// Borrow the value contained in the reference-counted box
63+
#[inline]
64+
pub fn borrow<'r>(&'r self) -> &'r T {
65+
unsafe { &(*self.ptr).value }
8566
}
8667
}
8768

8869
impl<T> Clone for Rc<T> {
89-
/// Return a shallow copy of the reference counted pointer.
9070
#[inline]
9171
fn clone(&self) -> Rc<T> {
9272
unsafe {
@@ -97,56 +77,75 @@ impl<T> Clone for Rc<T> {
9777
}
9878

9979
impl<T: DeepClone> DeepClone for Rc<T> {
100-
/// Return a deep copy of the reference counted pointer.
10180
#[inline]
10281
fn deep_clone(&self) -> Rc<T> {
103-
unsafe { Rc::new(self.borrow().deep_clone()) }
82+
unsafe { Rc::new_unchecked(self.borrow().deep_clone()) }
83+
}
84+
}
85+
86+
#[unsafe_destructor]
87+
impl<T> Drop for Rc<T> {
88+
fn drop(&mut self) {
89+
unsafe {
90+
if self.ptr.is_not_null() {
91+
(*self.ptr).count -= 1;
92+
if (*self.ptr).count == 0 {
93+
let _: ~RcBox<T> = transmute(self.ptr);
94+
}
95+
}
96+
}
10497
}
10598
}
10699

107100
#[cfg(test)]
108101
mod test_rc {
109102
use super::*;
110-
use std::cell::Cell;
103+
use cell::Cell;
111104

112105
#[test]
113106
fn test_clone() {
114-
let x = Rc::from_send(Cell::new(5));
115-
let y = x.clone();
116-
do x.borrow().with_mut_ref |inner| {
117-
*inner = 20;
107+
unsafe {
108+
let x = Rc::new_unchecked(Cell::new(5));
109+
let y = x.clone();
110+
do x.borrow().with_mut_ref |inner| {
111+
*inner = 20;
112+
}
113+
assert_eq!(y.borrow().take(), 20);
118114
}
119-
assert_eq!(y.borrow().take(), 20);
120115
}
121116

122117
#[test]
123118
fn test_deep_clone() {
124-
let x = Rc::from_send(Cell::new(5));
125-
let y = x.deep_clone();
126-
do x.borrow().with_mut_ref |inner| {
127-
*inner = 20;
119+
unsafe {
120+
let x = Rc::new_unchecked(Cell::new(5));
121+
let y = x.deep_clone();
122+
do x.borrow().with_mut_ref |inner| {
123+
*inner = 20;
124+
}
125+
assert_eq!(y.borrow().take(), 5);
128126
}
129-
assert_eq!(y.borrow().take(), 5);
130127
}
131128

132129
#[test]
133130
fn test_simple() {
134-
let x = Rc::from_freeze(5);
131+
let x = Rc::new(5);
135132
assert_eq!(*x.borrow(), 5);
136133
}
137134

138135
#[test]
139136
fn test_simple_clone() {
140-
let x = Rc::from_freeze(5);
137+
let x = Rc::new(5);
141138
let y = x.clone();
142139
assert_eq!(*x.borrow(), 5);
143140
assert_eq!(*y.borrow(), 5);
144141
}
145142

146143
#[test]
147144
fn test_destructor() {
148-
let x = Rc::from_send(~5);
149-
assert_eq!(**x.borrow(), 5);
145+
unsafe {
146+
let x = Rc::new_unchecked(~5);
147+
assert_eq!(**x.borrow(), 5);
148+
}
150149
}
151150
}
152151

@@ -171,21 +170,30 @@ pub struct RcMut<T> {
171170
priv ptr: *mut RcMutBox<T>,
172171
}
173172

174-
impl<T> RcMut<T> {
175-
unsafe fn new(value: T) -> RcMut<T> {
176-
RcMut{ptr: owned_to_raw(~RcMutBox{value: value, count: 1, borrow: Nothing})}
173+
impl<T: Freeze> RcMut<T> {
174+
/// Construct a new mutable reference-counted box from a `Freeze` value
175+
#[inline]
176+
pub fn new(value: T) -> RcMut<T> {
177+
unsafe { RcMut::new_unchecked(value) }
177178
}
178179
}
179180

180181
impl<T: Send> RcMut<T> {
182+
/// Construct a new mutable reference-counted box from a `Send` value
183+
#[inline]
181184
pub fn from_send(value: T) -> RcMut<T> {
182-
unsafe { RcMut::new(value) }
185+
unsafe { RcMut::new_unchecked(value) }
183186
}
184187
}
185188

186-
impl<T: Freeze> RcMut<T> {
187-
pub fn from_freeze(value: T) -> RcMut<T> {
188-
unsafe { RcMut::new(value) }
189+
impl<T> RcMut<T> {
190+
/// Unsafety construct a new mutable reference-counted box from any value.
191+
///
192+
/// It is possible to create cycles, which will leak, and may interact
193+
/// poorly with managed pointers.
194+
#[inline]
195+
pub unsafe fn new_unchecked(value: T) -> RcMut<T> {
196+
RcMut{ptr: transmute(~RcMutBox{value: value, count: 1, borrow: Nothing})}
189197
}
190198
}
191199

@@ -223,7 +231,7 @@ impl<T> Drop for RcMut<T> {
223231
if self.ptr.is_not_null() {
224232
(*self.ptr).count -= 1;
225233
if (*self.ptr).count == 0 {
226-
let _: ~T = cast::transmute(self.ptr);
234+
let _: ~RcMutBox<T> = transmute(self.ptr);
227235
}
228236
}
229237
}
@@ -247,7 +255,7 @@ impl<T: DeepClone> DeepClone for RcMut<T> {
247255
fn deep_clone(&self) -> RcMut<T> {
248256
do self.with_borrow |x| {
249257
// FIXME: #6497: should avoid freeze (slow)
250-
unsafe { RcMut::new(x.deep_clone()) }
258+
unsafe { RcMut::new_unchecked(x.deep_clone()) }
251259
}
252260
}
253261
}
@@ -270,7 +278,7 @@ mod test_rc_mut {
270278

271279
#[test]
272280
fn test_deep_clone() {
273-
let x = RcMut::from_freeze(5);
281+
let x = RcMut::new(5);
274282
let y = x.deep_clone();
275283
do x.with_mut_borrow |value| {
276284
*value = 20;
@@ -298,7 +306,7 @@ mod test_rc_mut {
298306

299307
#[test]
300308
fn modify() {
301-
let x = RcMut::from_freeze(5);
309+
let x = RcMut::new(5);
302310
let y = x.clone();
303311

304312
do y.with_mut_borrow |a| {
@@ -320,7 +328,7 @@ mod test_rc_mut {
320328

321329
#[test]
322330
fn release_mutable() {
323-
let x = RcMut::from_freeze(5);
331+
let x = RcMut::new(5);
324332
do x.with_mut_borrow |_| {}
325333
do x.with_borrow |_| {}
326334
}
@@ -340,7 +348,7 @@ mod test_rc_mut {
340348
#[test]
341349
#[should_fail]
342350
fn mutable_dupe() {
343-
let x = RcMut::from_freeze(5);
351+
let x = RcMut::new(5);
344352
let y = x.clone();
345353

346354
do x.with_mut_borrow |_| {
@@ -364,7 +372,7 @@ mod test_rc_mut {
364372
#[test]
365373
#[should_fail]
366374
fn restore_freeze() {
367-
let x = RcMut::from_freeze(5);
375+
let x = RcMut::new(5);
368376
let y = x.clone();
369377

370378
do x.with_borrow |_| {

src/libstd/std.rs

+1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ pub mod ptr;
129129
pub mod owned;
130130
pub mod managed;
131131
pub mod borrow;
132+
pub mod rc;
132133

133134

134135
/* Core language traits */

src/test/compile-fail/issue-7013.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
extern mod extra;
12-
use extra::rc::RcMut;
11+
use std::rc::RcMut;
1312

1413
trait Foo
1514
{
@@ -37,7 +36,7 @@ struct A
3736
fn main()
3837
{
3938
let a = A {v: ~B{v: None} as ~Foo}; //~ ERROR cannot pack type `~B`, which does not fulfill `Send`
40-
let v = RcMut::from_freeze(a); //~ ERROR instantiating a type parameter with an incompatible type
39+
let v = RcMut::new(a); //~ ERROR instantiating a type parameter with an incompatible type
4140
let w = v.clone();
4241
v.with_mut_borrow(|p| {p.v.set(w.clone());})
4342
}

src/test/compile-fail/no_send-rc.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::rc::Rc;
12+
13+
fn bar<T: Send>(_: T) {}
14+
15+
fn main() {
16+
let x = Rc::new(5);
17+
bar(x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::Rc<int>`, which does not fulfill `Send`
18+
}

src/test/compile-fail/rcmut-not-const-and-not-owned.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
extern mod extra;
11+
use std::rc::RcMut;
1212

1313
fn o<T: Send>(_: &T) {}
1414
fn c<T: Freeze>(_: &T) {}
1515

1616
fn main() {
17-
let x = extra::rc::RcMut::from_send(0);
18-
o(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Send`
19-
c(&x); //~ ERROR instantiating a type parameter with an incompatible type `extra::rc::RcMut<int>`, which does not fulfill `Freeze`
17+
let x = RcMut::from_send(0);
18+
o(&x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::RcMut<int>`, which does not fulfill `Send`
19+
c(&x); //~ ERROR instantiating a type parameter with an incompatible type `std::rc::RcMut<int>`, which does not fulfill `Freeze`
2020
}

0 commit comments

Comments
 (0)