# Proposals to support DST smart pointers

**URL:** <https://internals.rust-lang.org/t/proposals-to-support-dst-smart-pointers/21085>\
**Category:** language design\
**Created:** [June 26, 2024, 4:58pm UTC](https://internals.rust-lang.org/t/proposals-to-support-dst-smart-pointers/21085 "2024-06-26T16:58:27Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Rua](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rua/32/12169_2.png) [@Rua](https://internals.rust-lang.org/u/Rua)\
**Post date:** [June 26, 2024, 4:58pm UTC](https://internals.rust-lang.org/t/proposals-to-support-dst-smart-pointers/21085/1 "2024-06-26T16:58:27Z")

</div>

For a long time, there's not really been a sane way to construct custom dynamically-sized types (DSTs). They can't be constructed on the stack, so they must be constructed on the heap, but none of the standard library's heap-allocated containers can handle custom DSTs. `Box`, `Rc` and `Arc` can be constructed by moving a `Sized` type into them, or by constructing a slice of `MaybeUninit`, but nothing beyond that. `Box::from_raw` can take a pointer to a memory allocation, which you can in theory use to construct a DST before giving `Box` ownership of the memory, but `Rc` and `Arc` have no such option, as the pointer needed for their `from_raw` constructors can only be obtained from a previously constructed container.

I've thought about possible ways out of this tangle, but I'm not sure which one is the most promising option that I should pursue with a followup RFC.

## 1. Unsized unions

The main reason that the above containers can't be constructed with `MaybeUninit` for arbitrary types is that it's a union, and unions must be sized. You can have a `[MaybeUninit<T>]` but not a `MaybeUninit<[T]>`. I found some discussions about allowing (some subset of) unsized unions:

- [Zulip: t-opsem \> Unions with unsized fields](https://rust-lang.zulipchat.com/#narrow/stream/136281-t-opsem/topic/Unions.20with.20unsized.20fields)
- [Internals: Pre-Pre-RFC: Dynamically sized enum types](https://internals.rust-lang.org/t/pre-pre-rfc-dynamically-sized-enum-types/14605)
- [Internals: DST unions](https://internals.rust-lang.org/t/dst-unions/14420)

The most conservative would be to allow a union to contain exactly one unsized variant, just like structs. It could even be required to be the last, though for a union that seems superfluous. Because this would be a change to the core language itself, it probably has the most soundness ramifications, and therefore seems like the most likely to run into roadblocks and stall. But it also seems like this is the option everyone ultimately "wants" to happen in the long term.

## 2. `UniqueRcUninit`

[`UniqueRc`](https://doc.rust-lang.org/std/rc/struct.UniqueRc.html) is a relatively new and still unfinished API for constructing an `Rc`. It seems to have been added primarily for creating cyclic reference chains, but it could also be used to construct values in-place. In [Discord](https://discord.com/channels/273534239310479360/957720175619215380/1254540022334488656), @kpreid pointed me towards a private helper type for `UniqueRc`, called [`UniqueRcUninit`](https://github.com/rust-lang/rust/blob/4bdf8d2d5877f20b54c1506a607ad8c4744cc387/library/alloc/src/rc.rs#L3719), that was merged only a few days ago. Its purpose is to help with allocating memory for `UniqueRc`, and then providing some way to initialise it. If this were made public, and we added `BoxUninit` and `UniqueArcUninit`, then this could work around the limitations of unions. But as a private type it may not be suitable for a public API without some changes.

## 3. New allocation-only constructors

If neither of the above options are feasible, then there is a fallback option, which is to add a completely new API. A possible API was suggested in [Discord](https://discord.com/channels/273534239310479360/957720175619215380/1254502389176729751), with some adjustments by me:

```rust
impl<T> Rc<T>
where
    T: ?Sized + Pointee
{
    pub fn alloc(metadata: <T as Pointee>::Metadata) -> *mut T;
    pub unsafe fn dealloc(ptr: *mut T);
}

```

These functions would also be added to `Box` and `Arc`. Essentially, these functions would do the same with a manual raw pointer that `UniqueRcUninit` does as a custom type:

- The `alloc` constructor would allocate memory, and then return a raw pointer to the `T` within the allocation. This would be the same pointer that's returned by the `into_raw` method of these three types, but can be obtained without first obtaining a `Box`/`Rc`/`Arc` with an initialised `T`. The user would then use this pointer to initialise the `T`, and then call `from_raw` to create the final container.
- The `dealloc` function is needed in case construction of the `T` fails in some way, and the memory needs to be freed without ever initialising the memory and creating the container type.

Do you think any of these ideas is worth investigating further and turning into an RFC?

---

<div class="post-metadata">

**Author:** ![pitaj](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pitaj/32/11262_2.png) [@pitaj](https://internals.rust-lang.org/u/pitaj)\
**Post date:** [June 26, 2024, 6:19pm UTC](https://internals.rust-lang.org/t/proposals-to-support-dst-smart-pointers/21085/2 "2024-06-26T18:19:36Z")

</div>

To me, it seems like unsized unions would be the best option here. However, you would still need some way to allocate a `UniqueRc<MaybeUninit<[T]>>`. This would essentially mean copying the basic `MaybeUninit` APIs (`uninit`, `write`, etc) to all of those containers.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [June 26, 2024, 6:30pm UTC](https://internals.rust-lang.org/t/proposals-to-support-dst-smart-pointers/21085/3 "2024-06-26T18:30:15Z")

</div>

Once you have the `UniqueRc<MaybeUninit<[T]>>`, you can deref to get a `&mut MaybeUninit<[T]>` for purposes of initializing it. So, the only operations needed per container would be the initial and final ones:

- Allocate `Container<MaybeUninit<T>>`.
- Transform `Container<MaybeUninit<T>>` to `Container<T>`.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [September 24, 2024, 6:30pm UTC](https://internals.rust-lang.org/t/proposals-to-support-dst-smart-pointers/21085/4 "2024-09-24T18:30:47Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
