Skip to content

Commit f215346

Browse files
committed
auto merge of #16101 : kballard/rust/rc_unique_ownership, r=aturon
Add a few new free functions to alloc::rc for manipulating uniquely-owned Rc values. is_unique() can be used to test if the Rc is uniquely-owned, try_unwrap() can remove the value from a uniquely-owned Rc, and get_mut() can return a &mut for a uniquely-owned Rc. These are all free functions, because smart pointers should avoid having methods when possible. They can't be static methods because UFCS will remove that distinction. I think we should probably change downgrade() and make_unique() into free functions as well, but that's out of scope.
2 parents cd1216a + 192a8a5 commit f215346

File tree

1 file changed

+116
-9
lines changed

1 file changed

+116
-9
lines changed

src/liballoc/rc.rs

+116-9
Original file line numberDiff line numberDiff line change
@@ -150,18 +150,18 @@ fn main() {
150150

151151
#![stable]
152152

153-
use core::mem::transmute;
154153
use core::cell::Cell;
155154
use core::clone::Clone;
156155
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
157156
use core::default::Default;
157+
use core::fmt;
158158
use core::kinds::marker;
159+
use core::mem::{transmute, min_align_of, size_of, forget};
159160
use core::ops::{Deref, Drop};
160161
use core::option::{Option, Some, None};
161162
use core::ptr;
162163
use core::ptr::RawPtr;
163-
use core::mem::{min_align_of, size_of};
164-
use core::fmt;
164+
use core::result::{Result, Ok, Err};
165165

166166
use heap::deallocate;
167167

@@ -218,6 +218,76 @@ impl<T> Rc<T> {
218218
}
219219
}
220220

221+
/// Returns true if the `Rc` currently has unique ownership.
222+
///
223+
/// Unique ownership means that there are no other `Rc` or `Weak` values
224+
/// that share the same contents.
225+
#[inline]
226+
#[experimental]
227+
pub fn is_unique<T>(rc: &Rc<T>) -> bool {
228+
// note that we hold both a strong and a weak reference
229+
rc.strong() == 1 && rc.weak() == 1
230+
}
231+
232+
/// Unwraps the contained value if the `Rc` has unique ownership.
233+
///
234+
/// If the `Rc` does not have unique ownership, `Err` is returned with the
235+
/// same `Rc`.
236+
///
237+
/// # Example:
238+
///
239+
/// ```
240+
/// use std::rc::{mod, Rc};
241+
/// let x = Rc::new(3u);
242+
/// assert_eq!(rc::try_unwrap(x), Ok(3u));
243+
/// let x = Rc::new(4u);
244+
/// let _y = x.clone();
245+
/// assert_eq!(rc::try_unwrap(x), Err(Rc::new(4u)));
246+
/// ```
247+
#[inline]
248+
#[experimental]
249+
pub fn try_unwrap<T>(rc: Rc<T>) -> Result<T, Rc<T>> {
250+
if is_unique(&rc) {
251+
unsafe {
252+
let val = ptr::read(&*rc); // copy the contained object
253+
// destruct the box and skip our Drop
254+
// we can ignore the refcounts because we know we're unique
255+
deallocate(rc._ptr as *mut u8, size_of::<RcBox<T>>(),
256+
min_align_of::<RcBox<T>>());
257+
forget(rc);
258+
Ok(val)
259+
}
260+
} else {
261+
Err(rc)
262+
}
263+
}
264+
265+
/// Returns a mutable reference to the contained value if the `Rc` has
266+
/// unique ownership.
267+
///
268+
/// Returns `None` if the `Rc` does not have unique ownership.
269+
///
270+
/// # Example:
271+
///
272+
/// ```
273+
/// use std::rc::{mod, Rc};
274+
/// let mut x = Rc::new(3u);
275+
/// *rc::get_mut(&mut x).unwrap() = 4u;
276+
/// assert_eq!(*x, 4u);
277+
/// let _y = x.clone();
278+
/// assert!(rc::get_mut(&mut x).is_none());
279+
/// ```
280+
#[inline]
281+
#[experimental]
282+
pub fn get_mut<'a, T>(rc: &'a mut Rc<T>) -> Option<&'a mut T> {
283+
if is_unique(rc) {
284+
let inner = unsafe { &mut *rc._ptr };
285+
Some(&mut inner.value)
286+
} else {
287+
None
288+
}
289+
}
290+
221291
impl<T: Clone> Rc<T> {
222292
/// Acquires a mutable pointer to the inner contents by guaranteeing that
223293
/// the reference count is one (no sharing is possible).
@@ -227,11 +297,8 @@ impl<T: Clone> Rc<T> {
227297
#[inline]
228298
#[experimental]
229299
pub fn make_unique(&mut self) -> &mut T {
230-
// Note that we hold a strong reference, which also counts as
231-
// a weak reference, so we only clone if there is an
232-
// additional reference of either kind.
233-
if self.strong() != 1 || self.weak() != 1 {
234-
*self = Rc::new(self.deref().clone())
300+
if !is_unique(self) {
301+
*self = Rc::new((**self).clone())
235302
}
236303
// This unsafety is ok because we're guaranteed that the pointer
237304
// returned is the *only* pointer that will ever be returned to T. Our
@@ -260,7 +327,7 @@ impl<T> Drop for Rc<T> {
260327
if !self._ptr.is_null() {
261328
self.dec_strong();
262329
if self.strong() == 0 {
263-
ptr::read(self.deref()); // destroy the contained object
330+
ptr::read(&**self); // destroy the contained object
264331

265332
// remove the implicit "strong weak" pointer now
266333
// that we've destroyed the contents.
@@ -427,6 +494,7 @@ mod tests {
427494
use super::{Rc, Weak};
428495
use std::cell::RefCell;
429496
use std::option::{Option, Some, None};
497+
use std::result::{Err, Ok};
430498
use std::mem::drop;
431499
use std::clone::Clone;
432500

@@ -494,6 +562,45 @@ mod tests {
494562
// hopefully we don't double-free (or leak)...
495563
}
496564

565+
#[test]
566+
fn is_unique() {
567+
let x = Rc::new(3u);
568+
assert!(super::is_unique(&x));
569+
let y = x.clone();
570+
assert!(!super::is_unique(&x));
571+
drop(y);
572+
assert!(super::is_unique(&x));
573+
let w = x.downgrade();
574+
assert!(!super::is_unique(&x));
575+
drop(w);
576+
assert!(super::is_unique(&x));
577+
}
578+
579+
#[test]
580+
fn try_unwrap() {
581+
let x = Rc::new(3u);
582+
assert_eq!(super::try_unwrap(x), Ok(3u));
583+
let x = Rc::new(4u);
584+
let _y = x.clone();
585+
assert_eq!(super::try_unwrap(x), Err(Rc::new(4u)));
586+
let x = Rc::new(5u);
587+
let _w = x.downgrade();
588+
assert_eq!(super::try_unwrap(x), Err(Rc::new(5u)));
589+
}
590+
591+
#[test]
592+
fn get_mut() {
593+
let mut x = Rc::new(3u);
594+
*super::get_mut(&mut x).unwrap() = 4u;
595+
assert_eq!(*x, 4u);
596+
let y = x.clone();
597+
assert!(super::get_mut(&mut x).is_none());
598+
drop(y);
599+
assert!(super::get_mut(&mut x).is_some());
600+
let _w = x.downgrade();
601+
assert!(super::get_mut(&mut x).is_none());
602+
}
603+
497604
#[test]
498605
fn test_cowrc_clone_make_unique() {
499606
let mut cow0 = Rc::new(75u);

0 commit comments

Comments
 (0)