Skip to content

Add a conversion from &mut T to &mut UnsafeCell<T> #198

@joseph-gio

Description

@joseph-gio

Proposal

Problem statement

There should be a safe API that converts an &mut T reference into an &mut UnsafeCell<T> reference within a certain scope.

Motivation, use-cases

When dealing with exclusive references, sometimes you may wish to opt in to temporary shared mutable access. If your type implements Copy, you can use Cell::from_mut to convert a mutable reference to a Cell, which allows interior mutability. For non-Copy types, it is often required to use UnsafeCell to allow interior mutability. Converting from &mut T to &mut UnsafeCell<T> is always sound, however there is currently no safe way to do this so the user is required to use std::mem::transmute. Use of this function is potentially error-prone, as a simple mistake might result in the returned reference having an incorrect lifetime.

For an example of a situation where this would be useful, consider this code I wrote for the bevy game engine:

// SAFETY: Converting `&mut T` -> `&UnsafeCell<T>`
// is explicitly allowed in the docs for `UnsafeCell`.
let world: &'w UnsafeCell<World> = unsafe { std::mem::transmute(world) };
Func::combine(
    input,
    // SAFETY: Since these closures are `!Send + !Sync + !'static`, they can never
    // be called in parallel. Since mutable access to `world` only exists within
    // the scope of either closure, we can be sure they will never alias one another.
    |input| self.a.run(input, unsafe { world.deref_mut() }),
    |input| self.b.run(input, unsafe { world.deref_mut() }),
)

Solution sketches

We should add an associated fn to the UnsafeCell type:

pub fn from_mut(value: &mut T) -> &mut UnsafeCell<T> {
    // SAFETY: UnsafeCell is repr(transparent).
    unsafe { &mut *(value as *mut T as *mut Self) }
}

This returns &mut UnsafeCell<T>, unlike Cell::from_mut which returns &Cell. It was a mistake for Cell::from_mut to work this way, since exclusive references are more useful due to the {Unsafe}Cell::get_mut function.

Links and related work

What happens now?

This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions