Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add function Arc/Rc::as_weak(…) to convert &Arc/Rc<T> to &Weak<T> #1

Closed
wants to merge 2 commits into from

Conversation

jeremyBanks
Copy link
Owner

@jeremyBanks jeremyBanks commented Aug 12, 2022

I would like to propose the addition of a new as_weak associated function on Arc and Rc, taking a shared reference to a strong Arc/Rc and transmuting it into a shared reference to the corresponding Weak type.

Currently, if you have a strong Arc/Rc and you're calling a function that expects a &Weak, you'll need to .downgrade() to create a temporary Weak, incurring two additional writes to the backing allocation. This could be avoided if it were possible to convert an &Arc/&Rc to a &Weak directly, with a function like this:

impl<T: ?Sized> Arc<T> {
    pub const fn as_weak<'a>(this: &'a Self) -> &'a Weak<T> {
        unsafe { mem::transmute::<&'a Arc<T>, &'a Weak<T>>(this) }
    }
}

In memory, Arc/Rc and sync::Weak/rc::Weak are both represented by a NotNull pointer to the backing ArcInner/RcBox where the reference counts and inner value are actually stored. Whether a reference is strong or weak exists only at the type level, and the static guarantees provided by Weak (that the pointed-to allocation will exist, unless the pointer has the special non-aligned Weak::new value) are strictly weaker than those provided by Arc/Rc (that the pointed-to allocation will exist full-stop, and that the value inside that allocation will still be valid/will not have been dropped yet). The Arc/Rc do have a PhantomData<T> that the Weaks do not, but it's zero-size and shouldn't affect layout, only drop behaviour (which isn't relevant since the proposed function is for borrowed values).

This requires the addition of the #[repr(transparent)] attribute to Arc/Rc, and Weak in order to guarantee their memory layouts are identical. (#[repr(C)] might also work for that purpose, but I'm not sure if that would break the NonZero niche optimization.) According to the discussions at rust-lang#72841 (review), adding the #[repr] does not constitute a public interface change/commitment because the internal fields are still private (and with rust-lang#90435 such #[repr]s may be hidden from the docs in the future). So even if the #[repr(transparent)] were added, this function still couldn't be implemented in an external crate as the crate wouldn't be able to soundly rely on the layout remaining the same; this function can only be implemented in the standard library.

This implementation is gated behind a new #![feature(rc_as_weak)].


previous discussion: Rust Internals thread #17171, Stack Overflow question #73314967

@jeremyBanks jeremyBanks self-assigned this Aug 12, 2022
@jeremyBanks jeremyBanks changed the title {Arc,Rc}::as_weak(…) Marking Arc/Rc/Weak as #[repr(transparent)] Aug 12, 2022
@jeremyBanks jeremyBanks changed the title Marking Arc/Rc/Weak as #[repr(transparent)] Adds an associated function Arc/Rc::as_weak(…) to convert &Arc/Rc<T> to &Weak<T> Aug 13, 2022
@jeremyBanks jeremyBanks changed the title Adds an associated function Arc/Rc::as_weak(…) to convert &Arc/Rc<T> to &Weak<T> Add associated function Arc/Rc::as_weak(…) to convert &Arc/Rc<T> to &Weak<T> Aug 13, 2022
@jeremyBanks jeremyBanks changed the title Add associated function Arc/Rc::as_weak(…) to convert &Arc/Rc<T> to &Weak<T> Add function Arc/Rc::as_weak(…) to convert &Arc/Rc<T> to &Weak<T> Aug 13, 2022
Repository owner locked as resolved and limited conversation to collaborators Aug 13, 2022
@jeremyBanks jeremyBanks deleted the weeeeaaak branch August 13, 2022 05:03
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant