# Is custom allocators the right abstraction?

**URL:** https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460
**Category:** libs
**Created:** [November 28, 2020, 4:14pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460 "2020-11-28T16:14:15Z")
**Posts on this page:** 20
**Page:** 3

<div class="post-metadata">

### Author: ![TimDiekmann](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/timdiekmann/32/4669_2.png) [@TimDiekmann](https://internals.rust-lang.org/u/TimDiekmann)
#### Post date: [December 3, 2020, 5:14pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/41 "2020-12-03T17:14:10Z")

</div>

The storage have to return a pointer or a reference to the current value. The trait is looking similar to this:

```rust
pub trait Storage<T: ?Sized> {
    fn as_ptr(&self) -> *const T;
    fn as_mut_ptr(&mut self) -> *mut T;
}

```

For clarification, I'll use `AllocatorStorage<T: ?Sized, A: AllocRef>`. `Storage<T>` is implemented for `AllocatorStorage<T>`, so it returns a poitner to `T`. `Box`'s storage parameter defaults to `AllocatorStorage<T, Global>`, so calling `as_ptr` on the storage returns `T`. When creating a `Box` with `new_uninit`, the returned type is `Box<MaybeUninit<T>, AllocatorStorage<MaybeUninit<T>, A>>` so calling `Box::assume_init` requires to change the storage type. For `AllocatorStorage` this is basically casting the underlying pointer, but for other storages like `[MaybeUninit<T>; N]` a `mem::transmute` ([actually a workaround is required](https://github.com/rust-lang/rust/issues/61956)) is needed. Generally, this requires `memcpy`: [https://godbolt.org/z/47sxre](https://godbolt.org/z/47sxre)

I don't know what's the plan on this issue, maybe this case can be optimized out somehow. I'd go that route for now, but I'm not super happy with it.

---

<div class="post-metadata">

### Author: ![TimDiekmann](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/timdiekmann/32/4669_2.png) [@TimDiekmann](https://internals.rust-lang.org/u/TimDiekmann)
#### Post date: [December 3, 2020, 5:19pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/42 "2020-12-03T17:19:44Z")

</div>

> [@matthieum](#):
>
> As a result, I think that for `Box` , unlike for `Vec` or `VecDeque` , we need an **untyped** storage.

This may be a solution. Currently I'm using associative types instead of generics anyway, so `Storage` may not need a type at all. For "real" collections, we could use sth. like `ContiguousStorage<Value=T>`.

Does the `new_uninit` apply to anything else than `Box`, `Rc` and `Arc`? In other words: does it occur in any place, where contiguous storage is a thing?

> [@matthieum](#):
>
> construction fails. Do not pass Go. Do not collect $200.

😆

---

<div class="post-metadata">

### Author: ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)
#### Post date: [December 3, 2020, 5:37pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/43 "2020-12-03T17:37:34Z")

</div>

> [@TimDiekmann](#):
>
> `Box<MaybeUninit<T>, AllocatorStorage<MaybeUninit<T>, A>>` so calling `Box::assume_init` requires to change the storage type.

Is there a reason that `[MaybeUninit<T>; N]` can't just be used as the storage for `T`? In general, my understanding is that storages would deal in `MaybeUninit` anyway, and the container would be in charge of tracking initialization. This makes working with storages unsafe, but that's not that big of a deal, since they replace working with allocation, which is always unsafe.

---

<div class="post-metadata">

### Author: ![TimDiekmann](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/timdiekmann/32/4669_2.png) [@TimDiekmann](https://internals.rust-lang.org/u/TimDiekmann)
#### Post date: [December 3, 2020, 5:45pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/44 "2020-12-03T17:45:36Z")

</div>

This is working, you simply pass `[MaybeUninit<T>; N]` to the box, and it returns `Box<T, [MaybeUninit<T>; N]>`. However, how the `new_uninit` API would look like? Let's assume, we call it

```rust
fn new_uninit_in(storage: S) -> Box<MaybeUninit<T>, S>

```

What do you pass?

- `[MaybeUninit<T>; N]` derefs to `T`, so it can't be used
- `[MaybeUninit<MaybeUninit<T>>; N]` (urgh) derefs to `MaybeUninit<T>` (fine), but when calling `Box::assume_init` it requires the conversion from

```rust
Box<MaybeUninit<T>, [MaybeUninit<MaybeUninit<T>>; N]>

```

to

```rust
Box<T, [MaybeUninit<T>; N]>

```

which requires the storage to be changed.

Regardless, what is passed to `new_uninit`, it derefs to one specified type. Changing the type of the `Box` also requires the `Storage` to be changed to deref to the new type.

---

<div class="post-metadata">

### Author: ![TimDiekmann](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/timdiekmann/32/4669_2.png) [@TimDiekmann](https://internals.rust-lang.org/u/TimDiekmann)
#### Post date: [December 3, 2020, 5:52pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/45 "2020-12-03T17:52:05Z")

</div>

I don't know if the storage-API will work for `Box` (and similar) in general. As you noticed, those types can be used to store dynamically sized types. Since `impl Trait` in return position, it's probably not strictly needed anymore, but it's still have to be supported. However implementing `CoerceUnsized` for `Box` fails, as

> The trait `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced

but `Box<T, S>` don't store a field, which needs coercion, the data lives in `S`. Maybe I get something wrong here, I'm not a compiler expert, but it appears, that this won't work as of now.

---

<div class="post-metadata">

### Author: ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)
#### Post date: [December 3, 2020, 6:49pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/46 "2020-12-03T18:49:58Z")

</div>

> [@TimDiekmann](#):
>
> What do you pass?
> 
> - `[MaybeUninit<T>; N]` derefs to `T` , so it can't be used
> - `[MaybeUninit<MaybeUninit<T>>; N]` (urgh) derefs to `MaybeUninit<T>` (fine), but when calling `Box::assume_init` it requires the conversion from
> 
> ```rust
> Box<MaybeUninit<T>, [MaybeUninit<MaybeUninit<T>>; N]>
> 
> ```
> 
> to
> 
> ```rust
> Box<T, [MaybeUninit<T>; N]>
> 
> ```
> 
> which requires the storage to be changed.

Not necessarily, if you look on the main branch for `generic-vec`, you'll see that `impl<T, U, const N: usize> Storage<U> for UninitArray<T, N> { ... }` ([here](https://github.com/RustyYato/generic-vec/blob/6f251a5e95fdb5907f09a33716d180b3fd69d7d3/src/raw/array.rs#L62-L87)) where `T` and `U` could have very different sizes, but as long as the alignment of `UninitArray<T, N>` is larger than `U` it should be fine. For `Box` you'll also want the restriction that that the storage size is at least the same as `size_of::<U>()`.

~~(note: currently I have a bug where I don't check the alignments, but that will soon be fixed)~~ now fixed

---

<div class="post-metadata">

### Author: ![TimDiekmann](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/timdiekmann/32/4669_2.png) [@TimDiekmann](https://internals.rust-lang.org/u/TimDiekmann)
#### Post date: [December 4, 2020, 2:38pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/49 "2020-12-04T14:38:16Z")

</div>

I'll look into your implementation tomorrow. I think I have a solution to this, too but let's see...

Hopefully I'll find enough spare time to push this forward, it's by far the most promising proposal for collections I have seen!

* * *

> [@carbotaniuman](#):
>
> There's already the Allocator WG, so I don't think an RFC is really needed here - just do some exploration for the WG first without worrying about all the bureaucracy.

I [filed an issue](https://github.com/rust-lang/wg-allocators/issues/79) in the WG repository.

* * *

# Update:

I updated my crate to [v0.1.0](https://docs.rs/storages/0.1.0). It's may worth a look at [`RawBox`](https://docs.rs/storages/0.1.0/storages/boxed/struct.RawBox.html) and [`Box`](https://docs.rs/storages/0.1.0/storages/boxed/struct.Box.html). Main features:

- typed buffers with only two traits ([`Buffer`](https://docs.rs/storages/0.1.0/storages/buffer/trait.Buffer.html) and [`UnmanagedBuffer`](https://docs.rs/storages/0.1.0/storages/buffer/trait.UnmanagedBuffer.html))
- [`AllocatedBuffer`](https://docs.rs/storages/0.1.0/storages/buffer/struct.AllocatedBuffer.html) provided
- native arrays are supported
- Two APIs: raw API with call-side-dependency-injection and non-raw wrapper API, which behaves like the current api
- Coercion is working
- Unsized types are working

---

<div class="post-metadata">

### Author: ![adamnemecek](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/adamnemecek/32/6490_2.png) [@adamnemecek](https://internals.rust-lang.org/u/adamnemecek)
#### Post date: [December 8, 2020, 3:54am UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/50 "2020-12-08T03:54:22Z")

</div>

@TimDiekmann looking at the Storage trait, maybe we could consider adding AsPtr and AsMutPtr traits to the std. It feels cleaner than the Storage trait.

---

<div class="post-metadata">

### Author: ![TimDiekmann](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/timdiekmann/32/4669_2.png) [@TimDiekmann](https://internals.rust-lang.org/u/TimDiekmann)
#### Post date: [December 8, 2020, 10:41am UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/51 "2020-12-08T10:41:32Z")

</div>

I am not sure if it is worth it. Considering that pointer dereferencing is generally `unsafe` and `Storage` (or `Buffer` as it is called in my crate) is just a backend that the usual user will rarely interact with, I think a `Buffer` trait is more flexible. Of course, an `AsPtr`-trait could make sense in other places too, but I don't know how well it is backwards compatible.

I would stick with the `Buffer`-trait for now.

---

<div class="post-metadata">

### Author: ![carbotaniuman](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/carbotaniuman/32/6981_2.png) [@carbotaniuman](https://internals.rust-lang.org/u/carbotaniuman)
#### Post date: [December 8, 2020, 6:47pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/52 "2020-12-08T18:47:53Z")

</div>

How does this decide whether to use internal storage or the heap storage?

---

<div class="post-metadata">

### Author: ![Ericson2314](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ericson2314/32/246_2.png) [@Ericson2314](https://internals.rust-lang.org/u/Ericson2314)
#### Post date: [December 9, 2020, 2:10am UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/53 "2020-12-09T02:10:27Z")

</div>

I do fee likel @matklad's idea is a reason to switch back to `&mut self` or even `self` for allocators. With the allocators passed in at the last moment rather than stored, there is no longer the issue of storing allocators for multiple collections in a single threaded context. The dreaded `AllocOnce` `AllocMut` `Alloc` hierarchy can also come up based on whether it's a flat or non-flat data structure.

The main issue is it is also nice to pass in at deallocation time, but how to we prevent dropping without the allocator being passed in? This was my #1 reason for wanting linear types, years ago when I clamored about these things.

---

<div class="post-metadata">

### Author: ![matthieum](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthieum/32/4023_2.png) [@matthieum](https://internals.rust-lang.org/u/matthieum)
#### Post date: [December 9, 2020, 5:02pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/54 "2020-12-09T17:02:51Z")

</div>

This is massively invasive, requiring to change every single API, and requiring users to follow a very strict discipline since the same allocator _must_ be passed to every single call -- turning every single function into an `unsafe` function OR mandating that allocators be able to recognize their own allocations. Honestly, it seems completely impractical.

Note that even in Zig, where there is no global allocator, collections tend to capture the allocator in their constructor and use it throughout, including for destruction.

If you want to start exploring the possibility, I would kindly ask that you open a separate topic as your proposal is at the moonshot stage (not even a mini-draft/prototype, no experience that I can see) which means it'll require significant brainstorming to go anywhere.

---

<div class="post-metadata">

### Author: ![matklad](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matklad/32/12266_2.png) [@matklad](https://internals.rust-lang.org/u/matklad)
#### Post date: [December 9, 2020, 6:44pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/55 "2020-12-09T18:44:23Z")

</div>

Another interesting point here is that in Zig it's easier to handle "bring your own allocator"-style collections, because it uses value-based defer, rather than type-based destructors. So you, eg, can close over a single allocator local var to drop to local vars holding vectors.

---

<div class="post-metadata">

### Author: ![Wodann](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/wodann/32/7431_2.png) [@Wodann](https://internals.rust-lang.org/u/Wodann)
#### Post date: [December 24, 2020, 10:29am UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/56 "2020-12-24T10:29:56Z")

</div>

@TimDiekmann, have you been able to make headway with your reference implementation? It seems like an interesting concept to explore.

Thanks to @matthieum for raising this before we finalised the allocator API. It's always valuable to explore new avenues, at any point in the development process 😄

---

<div class="post-metadata">

### Author: ![TimDiekmann](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/timdiekmann/32/4669_2.png) [@TimDiekmann](https://internals.rust-lang.org/u/TimDiekmann)
#### Post date: [December 27, 2020, 12:53am UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/57 "2020-12-27T00:53:22Z")

</div>

I wasn't able to spend much more time recently so the repository is at the latest state. I'll investigate this further as soon as I find some spare time. 🙂

---

<div class="post-metadata">

### Author: ![matthieum](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthieum/32/4023_2.png) [@matthieum](https://internals.rust-lang.org/u/matthieum)
#### Post date: [December 28, 2020, 4:34pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/58 "2020-12-28T16:34:03Z")

</div>

I've been battling with trait representations.

It's easy enough to get the size and pointer of a slice, store the size and content separately, then reassemble them on the fly, however I could not find a (good) API for traits -- using `transmute_copy` on the unstable `TraitObject` representation is rather error-prone -- and more importantly I could not find a generic way to take a `?Sized` object, break it down into meta-data + data, and reassemble it.

The closest I've found is the `thin` crate, and by default it only handles a couple of traits (by implementing a custom trait for them).

I'm thinking we may be lacking a more fundamental API on which `RawBox<dyn Trait, 48>` can be built.

---

<div class="post-metadata">

### Author: ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)
#### Post date: [December 28, 2020, 4:39pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/59 "2020-12-28T16:39:22Z")

</div>

> [@matthieum](#):
>
> and more importantly I could not find a generic way to take a `?Sized` object, break it down into meta-data + data, and reassemble it.

There isn't one! That's what all these open RFCs are trying to achieve

> <https://github.com/rust-lang/rfcs/pull/2984>
>
> Those two new language traits are at the intersection of #1861, #2580, #2594, an…d this RFC's raison d'être is solely to try to get some progress for those 3 RFCs all at once by specifying their common core part.
> 
> \[Rendered\](https://github.com/nox/rust-rfcs/blob/patch-1/text/0000-pointee.md)

> <https://github.com/rust-lang/rfcs/pull/2594>
>
> This has been a long time coming - similar to #2580, but more general.
> 
> ~~On t…he unresolved question about \`?Sized -\> DynamicallySized\`, and the need for \`?DynamicallySized\`. I think this is actually a reasonable change which makes \`extern type\`s act much nicer around generic functions that already exist, and fixes all the Rust code that has been written already. No longer is, for example, \`Box\<extern-type\>\` allowed.~~ I've chosen to make this change.
> 
> Note that \`DynamicallySized\` is a new language trait, on the level of \`Sized\` and \`Copy\`.
> 
> \[Rendered\](https://github.com/ubsan/rust-rfcs/blob/custom-dst/text/0000-custom-dst.md)

> <https://github.com/rust-lang/rfcs/pull/2580>
>
> Add generic APIs that allow manipulating the metadata of fat pointers:
> 
> \* Nami…ng the metadata’s type (as an associated type)
> \* Extracting metadata from a pointer
> \* Reconstructing a pointer from a data pointer and metadata
> \* Representing vtables, the metadata for trait objects, as a type with some limited API
> 
> This RFC does \*not\* propose a mechanism for defining custom dynamically-sized types, but tries to stay compatible with future proposals that do.
> 
> \[Rendered\](https://github.com/rust-lang/rfcs/blob/master/text/2580-ptr-meta.md)

Even some closed ones

> <https://github.com/rust-lang/rfcs/pull/2310>
>
> \[Rendered\](https://github.com/kennytm/rfcs/blob/dyn-sized/text/0000-dyn-sized.md…)
> 
> cc #2255 
> cc @mikeyhew, @mystor (#1993), @withoutboats

> <https://github.com/rust-lang/rfcs/pull/1524>
>
> I believe this fixes #813, and is a nicer, and far more powerful, solution than …#709.

---

<div class="post-metadata">

### Author: ![matthieum](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthieum/32/4023_2.png) [@matthieum](https://internals.rust-lang.org/u/matthieum)
#### Post date: [December 29, 2020, 12:57pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/60 "2020-12-29T12:57:33Z")

</div>

I left a comment on [RFC 2984](https://github.com/rust-lang/rfcs/pull/2984#issuecomment-752065665) which I think is the most minimal.

A straightforward extension to the RFC is all it takes to be able to break down a pointer into its raw parts (meta-data and pointer to data) and stitch them back together afterwards.

---

<div class="post-metadata">

### Author: ![matthieum](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matthieum/32/4023_2.png) [@matthieum](https://internals.rust-lang.org/u/matthieum)
#### Post date: [January 3, 2021, 2:04pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/61 "2021-01-03T14:04:05Z")

</div>

I'd like to point to you [Coca's author experiments](https://gist.github.com/teryror/7b9a23fd0cd8dcfbcb6ebd34ee2639f8).

Of particular interest is the use of the `set_ptr_value` feature to reset the data-pointer of a fat-pointer. By using it, @teryror manages to handle `Sized`, slices, and traits in a generic manner (preserving their meta-data).

It's not ideal as the original pointer is dead-weight, adding up an extra 8 bytes, however it's working right now which is nice to further explore the API design.

---

<div class="post-metadata">

### Author: ![Ericson2314](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ericson2314/32/246_2.png) [@Ericson2314](https://internals.rust-lang.org/u/Ericson2314)
#### Post date: [January 7, 2021, 11:32pm UTC](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460/62 "2021-01-07T23:32:33Z")

</div>

> [@matklad](#):
>
> values-based defer

Oh....shit. I spent ages haranguing people about how we would need linear types for this issue. But linear types that simply require all bindings be `defer`-ed rather than only working with out unwinding would probably get much less push-back, and are _exactly_ what this needs.

(To be precise, it's the unwinding that requires the defer, not the linear-typed values themselves, but people were and presumably are uncomfortable with no-unwinding changing the language that deeply, so I won't go there.)

I most certainly do not have the bandwidth to write this RFC, but someone else probably should. It will make custom allocator stuff 100x better.

[Previous page](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460.md?page=2)

[Next page](https://internals.rust-lang.org/t/is-custom-allocators-the-right-abstraction/13460.md?page=4)
