Rollup merge of #109026 - joshtriplett:rc-into-inner, r=dtolnay

Introduce `Rc::into_inner`, as a parallel to `Arc::into_inner`

Unlike `Arc`, `Rc` doesn't have the same race condition to avoid, but
maintaining an equivalent API still makes it easier to work with both
`Rc` and `Arc`.
This commit is contained in:
Matthias Krüger 2023-03-12 20:44:50 +01:00 committed by GitHub
commit b28775cdcb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 0 deletions

View File

@ -681,6 +681,24 @@ impl<T> Rc<T> {
Err(this)
}
}
/// Returns the inner value, if the `Rc` has exactly one strong reference.
///
/// Otherwise, [`None`] is returned and the `Rc` is dropped.
///
/// This will succeed even if there are outstanding weak references.
///
/// If `Rc::into_inner` is called on every clone of this `Rc`,
/// it is guaranteed that exactly one of the calls returns the inner value.
/// This means in particular that the inner value is not dropped.
///
/// This is equivalent to `Rc::try_unwrap(...).ok()`. (Note that these are not equivalent for
/// `Arc`, due to race conditions that do not apply to `Rc`.)
#[inline]
#[unstable(feature = "rc_into_inner", issue = "106894")]
pub fn into_inner(this: Self) -> Option<T> {
Rc::try_unwrap(this).ok()
}
}
impl<T> Rc<[T]> {

View File

@ -151,6 +151,21 @@ fn try_unwrap() {
assert_eq!(Rc::try_unwrap(x), Ok(5));
}
#[test]
fn into_inner() {
let x = Rc::new(3);
assert_eq!(Rc::into_inner(x), Some(3));
let x = Rc::new(4);
let y = Rc::clone(&x);
assert_eq!(Rc::into_inner(x), None);
assert_eq!(Rc::into_inner(y), Some(4));
let x = Rc::new(5);
let _w = Rc::downgrade(&x);
assert_eq!(Rc::into_inner(x), Some(5));
}
#[test]
fn into_from_raw() {
let x = Rc::new(Box::new("hello"));