rust-lang / libs-team

The home of the library team
Apache License 2.0
115 stars 18 forks source link

Add `try_into_boxed` (and potentially `into_boxed_inner`) for `Rc<T>`/`Arc<T>` where `T: ?Sized` #269

Closed Kolsky closed 3 months ago

Kolsky commented 11 months ago

Proposal

Problem statement

Currently there is no stable way to convert Rc/Arc<dyn Trait> to Box<dyn Trait> even though Box -> Rc/Arc is covered by a From implementation, and both into_inner/try_unwrap are there as well. Even a manual nightly solution has a lot of soundness footguns.

Motivating examples or use cases

A lot of UI-oriented API's use Arcs for widget trees (an example being druid). They might be able to benefit from having object-safe methods taking Box<Self> during tree updates. Any pattern where bulk multithreaded operations happen on Arcs happen to have synchronous execution inbetween should be a good fit for conversions of this sort. Even when T: Sized, an extra cost of moving the value is associated with unwrapping then boxing, which can be a detriment for big data structures (the case with arrays can usually be solved by cloning to Vec before resorting to TryFrom).

Solution sketch

I propose adding a private function

impl<T: ?Sized> Box<T> {
    unsafe fn read_unsized(ptr: *const T) -> Self;
}

mirroring pointer API, and then closely following implementation of try_unwrap, with the replacement of ptr::read by Box::read_unsized.

Alternatives

There is a crate called rc-box made by CAD97 with over 100'000 downloads. Overall it's a better solution for modifying uniquely owned Arc without resorting to calling get_mut each time (+more typesafe), and, unlike Arc -> Box, it avoids reallocation. However, it's not object safe, and it can only produce semantics of into_boxed_inner (otherwise DerefMut would be unsound).

Implementing the conversion manually has to resort to a nightly feature ptr_metadata and is very dangerous just for into_inner_boxed.

Links and related work

An old URLO thread

programmerjake commented 11 months ago

seems like UniqueArc would be a good alternative...it's not in nightly yet, but the Rc version is: UniqueRc

Amanieu commented 3 months ago

We discussed this and think that #90 may be a better solution to this problem. Feel free to reopen if you think that doesn't adequately address your use case.