Skip to content
25 changes: 25 additions & 0 deletions library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ struct RcBox<T: ?Sized> {
#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_insignificant_dtor]
#[repr(transparent)]
pub struct Rc<T: ?Sized> {
ptr: NonNull<RcBox<T>>,
phantom: PhantomData<RcBox<T>>,
Expand Down Expand Up @@ -933,6 +934,29 @@ impl<T: ?Sized> Rc<T> {
Weak { ptr: this.ptr }
}

/// Convert a reference to an [`Rc`] into a reference to a [`Weak`] of the same type.
///
/// This is a type-only operation; it doesn't modify the inner reference counts.
///
/// # Examples
///
/// ```
/// #![feature(rc_as_weak)]
///
/// use std::rc::{Rc, Weak};
///
/// let five: &Rc<i32> = &Rc::new(5);
///
/// let weak_five: &Weak<i32> = Rc::as_weak(five);
/// ```
#[inline]
#[unstable(feature = "rc_as_weak", issue = "100472")]
#[must_use]
pub const fn as_weak(this: &Self) -> &Weak<T> {
let weak = this as *const Self as *const Weak<T>;
unsafe { &*weak }
}

/// Gets the number of [`Weak`] pointers to this allocation.
///
/// # Examples
Expand Down Expand Up @@ -2143,6 +2167,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I {
///
/// [`upgrade`]: Weak::upgrade
#[stable(feature = "rc_weak", since = "1.4.0")]
#[repr(transparent)]
pub struct Weak<T: ?Sized> {
// This is a `NonNull` to allow optimizing the size of this type in enums,
// but it is not necessarily a valid pointer.
Expand Down
4 changes: 4 additions & 0 deletions library/alloc/src/rc/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ fn test_weak_count() {
let w = Rc::downgrade(&a);
assert!(Rc::strong_count(&a) == 1);
assert!(Rc::weak_count(&a) == 1);
let r: &Weak<i32> = Rc::as_weak(&a);
assert!(Rc::strong_count(&a) == 1);
assert!(Rc::weak_count(&a) == 1);
assert!(r.as_ptr() == Rc::as_ptr(&a));
drop(w);
assert!(Rc::strong_count(&a) == 1);
assert!(Rc::weak_count(&a) == 0);
Expand Down
25 changes: 25 additions & 0 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ macro_rules! acquire {
/// [rc_examples]: crate::rc#examples
#[cfg_attr(not(test), rustc_diagnostic_item = "Arc")]
#[stable(feature = "rust1", since = "1.0.0")]
#[repr(transparent)]
pub struct Arc<T: ?Sized> {
ptr: NonNull<ArcInner<T>>,
phantom: PhantomData<ArcInner<T>>,
Expand Down Expand Up @@ -282,6 +283,7 @@ impl<T: ?Sized> Arc<T> {
///
/// [`upgrade`]: Weak::upgrade
#[stable(feature = "arc_weak", since = "1.4.0")]
#[repr(transparent)]
pub struct Weak<T: ?Sized> {
// This is a `NonNull` to allow optimizing the size of this type in enums,
// but it is not necessarily a valid pointer.
Expand Down Expand Up @@ -959,6 +961,29 @@ impl<T: ?Sized> Arc<T> {
}
}

/// Convert a reference to an [`Arc`] into a reference to a [`Weak`] of the same type.
///
/// This is a type-only operation; it doesn't modify the inner reference counts.
///
/// # Examples
///
/// ```
/// #![feature(rc_as_weak)]
///
/// use std::sync::{Arc, Weak};
///
/// let five: &Arc<i32> = &Arc::new(5);
///
/// let weak_five: &Weak<i32> = Arc::as_weak(five);
/// ```
#[inline]
#[unstable(feature = "rc_as_weak", issue = "100472")]
#[must_use]
pub const fn as_weak(this: &Self) -> &Weak<T> {
let weak = this as *const Self as *const Weak<T>;
unsafe { &*weak }
}

/// Gets the number of [`Weak`] pointers to this allocation.
///
/// # Safety
Expand Down
4 changes: 4 additions & 0 deletions library/alloc/src/sync/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,10 @@ fn test_weak_count() {
let w = Arc::downgrade(&a);
assert!(Arc::strong_count(&a) == 1);
assert!(Arc::weak_count(&a) == 1);
let r: &Weak<i32> = Arc::as_weak(&a);
assert!(Arc::strong_count(&a) == 1);
assert!(Arc::weak_count(&a) == 1);
assert!(r.as_ptr() == Arc::as_ptr(&a));
let x = w.clone();
assert!(Arc::weak_count(&a) == 2);
drop(w);
Expand Down