# \[Pre-RFC\] Improved Unsizing

**URL:** https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861
**Category:** language design
**Created:** [June 21, 2022, 3:48pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861 "2022-06-21T15:48:42Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![CraftSpider](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/craftspider/32/7551_2.png) [@CraftSpider](https://internals.rust-lang.org/u/CraftSpider)
#### Post date: [June 21, 2022, 3:48pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/1 "2022-06-21T15:48:42Z")

</div>

# Summary

There is currently a lot of pain around unsizing and custom unsized types in Rust. This proposal does not attempt to address every possible use-case or problem around the current system, but does attempt to address several current limitations in terms of improving existing tools. It does this by loosening restrictions on several existing unstable traits.

# Motivation

Currently, writing custom unsized types in Rust is very painful. To initialize one tends to require large amounts of unsafe code, and to write items handling them is similarly painful, due to restrictions on CoerceUnsized. This proposal does not fix all use cases, but does make initializing custom unsized types and writing wrappers for them significantly less painful in some common cases.

# Guide-Level Explanation

## `Unsize` Changes

`Unsize` can now be implemented (following normal trait impl rules) by users on types that fulfill the following conditions, given a pair of types `T: Sized` and `U: !Sized`:

- `T` has the same repr as `U`
- `T` has the same fields as `U`, excepting the last field
- The scope within which the `Unsize` impl resides can 'see' all of both `T` and `U`'s fields. Same module for private fields, same crate for `pub(crate)` fields, dependent crates for public fields
  - For items from other crates, `U` must be exhaustive

- for `T`'s last field `TLast` and `U`'s last field `ULast`, `TLast: Unsize<ULast>`

### Examples

The following examples result in a type that can be unsized into another succesfully:

```rs
pub struct Object {
    name: String,
    fields: [*const Field],
}

pub struct SizedObject<const N: usize> {
    name: String,
    fields: [*const Field; N],
}

impl<const N: usize> Unsize<Object> for SizedObject<N> {}

```

```rs
#[repr(C)]
pub struct DebugableItem {
    count: i32,
    debug: dyn Debug,
}

#[repr(C)]
pub struct Field1 {
    count: i32,
    name: String,
}

impl Unsize<DebugableItem> for Field1 {}

#[repr(C)]
pub struct Field2 {
    count: i32,
    idx: i32,
}

impl Unsize<DebugableItem> for Field2 {}

```

The following examples do not result in a type that can be unsized into another:

```rs
#[repr(C)]
pub struct CSlice([u8]);

pub struct RustSlice<const N: usize>([u8; N]);

// Errors: repr mismatch
impl<const N: usize> Unsize<CSlice> for RustSlice<N> {}

```

```rs
mod private {
    pub struct Foo {
        a: [bool],
    }
}

pub struct Bar {
    a: [bool; 10],
}

// Error: Foo fields no visible
impl Unsize<Foo> for Bar {}

```

## `CoerceUnsized` Changes

`CoerceUnsized` will no longer be limited to only being implemented on structs. Enums will be allowed to implement it, given that they follow the following rules:

- The type to coerce (`T`) exists at least once in a non-phantomdata field in the enum
- `T` exists at most once in a non-phantomdata field in each variant
- Given each variant containing a type using `T`, and the type to coerce to (`U`), `CoerceUnsized<Foo<U>> for CoerceUnsized<Foo<T>>` must be implemented for the containing type

### Examples

The following examples compile successfully

```rs
pub enum MaybeMut<T> {
    Foo(*const T),
    Bar(*mut T),
}

impl CoerceUnsized<MaybeMut<U>> for MaybeMut<T>
where
    T: ?Sized + Unsize<U>,
    U: ?Sized,
{}

```

```rs
pub enum CoercableOption<T> {
    Some(&mut T),
    None,
}

impl CoerceUnsized<CoercableOption<U>> for CoercableOption<T>
where
    T: ?Sized + Unsize<U>,
    U: ?Sized,
{}

```

The following examples do not

```rust
pub enum MissingT<T> {
    Foo(i32),
    Bar(bool),
}

impl CoerceUnsized<MissingT<U>> for MissingT<T>
where
    T: ?Sized + Unsize<U>,
    U: ?Sized,
{}

```

```rs
pub enum TooManyT<T> {
    Field(*const T, *mut T),
    Missing,
}

impl CoerceUnsized<TooManyT<U>> for TooManyT<T>
where
    T: ?Sized + Unsize<U>,
    U: ?Sized,
{}

```

# Reference-level explanation

## `Unsize` Changes

The compiler already automatically generates all `Unsize` impls, this proposal will simply expand the cases it works on. The code generated should look similar to existing generated code.

## `CoerceUnsized` Changes

The code generated by the compiler for coerce-unsizing enums will follow a fairly simple format:

```rust
match self {
    Var1 { field_0, .., field_n } => Var1 { field_0, .., field_n as &mut U },
    ..,
    VarN { field_0, .., field_n } => VarN { field_0 as &U, .., field_n },
}

```

# Drawbacks

TODO

# Alternatives

- User-controlled unsizing
  - Limits ergonomics, no `Box::new(foo) as Box<Bar>`
  - Requires unsafe to implement, manual allocation

# Unresolved questions

- Should any more situations be restricted/allowed?
  - Should downstream crates never implement `Unsize<Upstream>`?

- Will this lock us out of any future alternatives?

# Future Possibilities

- Allowing unsizing based on fields (len field in a struct)

---

<div class="post-metadata">

### Author: ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)
#### Post date: [June 21, 2022, 3:50pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/2 "2022-06-21T15:50:43Z")

</div>

> [@CraftSpider](#):
>
> `CoerceUnsized` will no longer be limited to only being implemented on structs. Enums will be allowed to implement it, given that they follow the following rules:

I believe the issue with enums implementing `CoerceUnsized` is that it will make calculating the offset of fields a lot harder due to potential alignment differences between variants.

---

<div class="post-metadata">

### Author: ![CraftSpider](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/craftspider/32/7551_2.png) [@CraftSpider](https://internals.rust-lang.org/u/CraftSpider)
#### Post date: [June 21, 2022, 4:31pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/3 "2022-06-21T16:31:44Z")

</div>

Is this 'difficult to implement' or 'impractical to implement'?

I think that allowing this kind of coercion would be worth difficulty, as I've had at least 2 projects it would be useful for, but on the other hand, I understand hesitancy if it looks like it would slow down common cases, or just take someone time they'd rather not spend. I'd also be willing to put in some work to implement this - I'm not super familiar with the Rust code base, but it wouldn't be my first contribution.

---

<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: [June 21, 2022, 5:46pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/4 "2022-06-21T17:46:56Z")

</div>

> [@CraftSpider](#):
>
> The following examples result in a type that can be unsized into another succesfully:
> 
> ```rust
> pub struct Object {
> name: String,
> fields: [*const Field],
> }
> 
> // Can unsize into Object
> pub struct SizedObject<const N: usize> {
> name: String,
> fields: [*const Field; N],
> }
> 
> ```

This seems like a back-compat hazard if this coercion is allowed outside the crate. I would prefer if there was some annotation to allow this coercion outside the given crate/module.

---

<div class="post-metadata">

### Author: ![CraftSpider](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/craftspider/32/7551_2.png) [@CraftSpider](https://internals.rust-lang.org/u/CraftSpider)
#### Post date: [June 21, 2022, 6:17pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/5 "2022-06-21T18:17:21Z")

</div>

The restrictions that all fields must be pub and the structs must be non-exhaustive is designed to require that changing the type or layout of the fields would already be a back-compat issue. Are there any cases where all fields are public and the struct is exhaustive that would be allowed before but not after this change?

---

<div class="post-metadata">

### Author: ![CraftSpider](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/craftspider/32/7551_2.png) [@CraftSpider](https://internals.rust-lang.org/u/CraftSpider)
#### Post date: [June 21, 2022, 6:56pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/6 "2022-06-21T18:56:39Z")

</div>

To be clear: I'm not fully against an annotation, but I was hoping to design the rules such that it wasn't necessary.

---

<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: [June 21, 2022, 7:06pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/7 "2022-06-21T19:06:22Z")

</div>

> [@CraftSpider](#):
>
> ```rust
> pub struct Object {
> name: String,
> fields: [*const Field],
> }
> 
> // Can unsize into Object
> pub struct SizedObject<const N: usize> {
> name: String,
> fields: [*const Field; N],
> }
> 
> ```

Just to be clear, the above snippet would automatically create the following impl right?

```rust
impl Unsize<Object> for SizedObject {} 

```

so a downstream crate could do the following:

```rust
fn unsize_me(obj: &SizedObject) -> &Object { obj }

```

Because of that automatic implementation and the fact that we can't restrict impls to be crate local. So this isn't as straightforward as it seems.

Perhaps there's another solution, where instead of relying on `Unsize` it's just some builtin, but that seems to duplicate much of the work that `Unsize` does, so it may not be desirable.

---

<div class="post-metadata">

### Author: ![CraftSpider](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/craftspider/32/7551_2.png) [@CraftSpider](https://internals.rust-lang.org/u/CraftSpider)
#### Post date: [June 21, 2022, 7:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/8 "2022-06-21T19:41:39Z")

</div>

I wanted to use `Unsize` because it's the standard way to write generic functions that accept unsizable types. I don't want to force duplication of functions, with `unsize_builtin` vs `unsize_user`. The impl is correct, and the exact purpose of this change - to allow user-defined types to be unsized. (Also why this is an RFC - The change would be immediately visible to stable users)

It may be possible to require an attribute on user types to generate impls for them. On the other hand, how popular are user-defined unsized types with matching definitions in a visible scope? In other words, how likely is it that people write code that looks like that today? Requiring an `#[allow_unsize]` attribute (your first suggestion) would fix both your mentioned issues at once - to unsize, the definer must allow it, and with what you've just said I'm starting to come around to the idea.

---

<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: [June 21, 2022, 8:06pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/9 "2022-06-21T20:06:39Z")

</div>

As opposed to `#[allow_unsize]`, I'd propose "just" allowing to write `impl Unsize<Object> for SizedObject {}`. (Then I'm sure a proc-macro would pop up to package that into an attribute/derive would pop up fairly quickly.)

At an impl level, the unsizing conversion would be implemented based on field visibility. However, actually using it is gated behind a `CoerceUnsized` implementation, which are all (required\[1\] by the compiler to be) gated on `T: Unsize<U>`. This would require checking that no coersions bypass a `CoerceUnsized` check (e.g. for primitive types e.g. references, pointers) but would AIUI be a minimal change to the compiler.

(For the duplicated functions, we currently have [https://lib.rs/crates/unsize.](https://lib.rs/crates/unsize.))

Also just for reference so I don't forget again when viewing this:

- `CoerceUnsize` is for containers, e.g. `&T: CoerceUnsize<&U> where T: Unsize<U>`
- `Unsize` is for objects, e.g. `[T; N]: Unsize<[T]>`

* * *

1. Caveat: I'm [working on adding](https://github.com/rust-lang/rust/pull/97052) `impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<JustMetadata<U>> for JustMetadata<T> {}` to coerce `<T as Pointee>::Metadata` to `<U as Pointee>::Metadata`. I forget whether it's emitting the obligation that `T: Unsize<U>` (but it's still necessarily provided as part of the impl).

---

<div class="post-metadata">

### Author: ![CraftSpider](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/craftspider/32/7551_2.png) [@CraftSpider](https://internals.rust-lang.org/u/CraftSpider)
#### Post date: [June 21, 2022, 8:09pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/10 "2022-06-21T20:09:22Z")

</div>

Ooh, I like that idea. Allow manual implementations of the `Unsize` marker, which the compiler checks for validity.

---

<div class="post-metadata">

### Author: ![CraftSpider](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/craftspider/32/7551_2.png) [@CraftSpider](https://internals.rust-lang.org/u/CraftSpider)
#### Post date: [June 22, 2022, 1:02am UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/11 "2022-06-22T01:02:17Z")

</div>

Updated for manual `Unsize` instead of automatic

---

<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: [June 22, 2022, 4:42am UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/12 "2022-06-22T04:42:28Z")

</div>

> [@CraftSpider](#):
>
> The scope within which `T` resides can 'see' all of `U`'s fields. Same module for private fields, some crate for `pub(crate)` fields, user-defined types for public fields

Now that you're using an `impl Unsize`, I'd change this to be that all of the fields (in both `T` and `U`) are visible from the location of the `impl`.

> [@CraftSpider](#):
>
> `T` has the same repr as `U`

Note that this is probably more restrictive than you intend: `#[repr(Rust)]` types _never_ have the same representation as another `#[repr(Rust)]` type. Consider the following example where this is the case today:

```rust
struct T {
    head: u8,
    tail: [u16; 2],
}

struct U {
    head: u8,
    tail: [u16]
}

```

`T` will actually likely be laid out as

```rust
// this is an implementation detail of rustc
#[repr(C)]
struct T {
    tail: [u16: 2],
    head: u8,
}

```

reordering the higher alignment fields to the front of the struct to minimize padding. As unsized fields are (as a current restriction of rustc) required to be the last field of a struct, unsizing generic types only works because (as a current implementation detail of rustc) `Unsize` generic types are always placed at the end of the struct, and the other fields are layout optimized ignoring it.

(In practice I _think_ this never results in layout pessimisation, and it's just a difference of where the padding goes, since we requiring padding to alignment? I don't have a proof, just a gut feeling from trying to think of a counterexample for a minute.)

If the intent is to allow unsizing `#[repr(Rust)]` types, then the RFC should at least mention the new layout constraint on them (if the last field is `Unsize` it can't be reordered) and potentially an assertion that this does not negatively impact layout optimizations.

> [@CraftSpider](#):
>
> ## `Unsize` Changes
> 
> The compiler already automatically generates all `Unsize` impls, this proposal will simply expand the cases it works on. The code generated should look similar to existing generated code, just with other struct fields copied into the new item.

Note that unsizing implementations are not copies; rather, they're instructions on how to create the correct pointee metadata to turn `dataptr` into `(dataptr, metadata)`.

> [@CraftSpider](#):
>
> # Future Possibilities
> 
> - Allowing unsizing based on fields (len field in a struct)

Note that I have [an open PR](https://github.com/rust-lang/rust/pull/97052) to implement `CoerceUnsized` for `JustMetadata<T>` (which is a newtype around `<T as Pointee>::Metadata`). I don't know exactly what you're envisioning here, but it'll probably need to use `JustMetadata<T>` for the same reason `CoerceUnsized` directly on metadata types is problematic (what does `(): CoerceUnsized<usize>` even mean?).

* * *

Also I scared myself temporarily about _`Unsize`_ on enums, which would be quite problematic in the face of enum discriminant optimizations/niching.

---

<div class="post-metadata">

### Author: ![CraftSpider](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/craftspider/32/7551_2.png) [@CraftSpider](https://internals.rust-lang.org/u/CraftSpider)
#### Post date: [June 23, 2022, 6:02pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/13 "2022-06-23T18:02:34Z")

</div>

Updated all but the repr commentary. I'm not 100% on the best way to resolve that, as I'm not super familiar with Rust's current layout algorithm. My instinct for it not causing issues is that the field to unsize must be the last one in the struct. That means that there will never be a field _after_ it that would want to reorder to _before_ it. Thus any that it would re-order before will either fill the padding exactly either way, or, would require the end be padded to length anyways. So this is a safe restriction as long as it only applies to the final field.

```rust
// This has size 4 either way
struct Foo {
    a: u8,
    b: u8,
    c: [u16; 2],
}

// The tail has no size - no advantage to moving it
struct Bar {
    a: u8,
    c: [u64; 0],
}

```

---

<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: [June 24, 2022, 6:22am UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/14 "2022-06-24T06:22:49Z")

</div>

> [@CraftSpider](#):
>
> That means that there will never be a field _after_ it that would want to reorder to _before_ it.

There could be a field _before_ it that wants to reorder _after_ it to minimize padding.

The theorem to prove is that given any layout, you can construct a layout at least as good with the desired field in the unsizing location.

> **A failed partial proof**
>
> In the document, we use the definition of `a mod b` for integer `a`, positive integer `b` as the smallest _nonnegative_ integer `x` where `(a - x) / b = 0`.
> 
> For convenience, we define `a amod b` as `-a mod b`.
> 
> For convenience, we define `a ~ b` as the smallest integer `x ≥ a` where `x mod b = 0`.
> 
> Lemma 1: `a ~ b = a + (a amod b)`.
> 
> Proof left to the reader.
> 
> Lemma 2: For any nonnegative `a`:  
> Lemma 2.1: `a mod b ≤ a`.  
> Lemma 2.2: `a amod b ≤ a`.  
> Lemma 2.3: `a mod b ≤ b`.  
> Lemma 2.4: `a amod b ≤ b`.
> 
> Proof left to the reader. Trivial.
> 
> Theorem: It is always possible to reorder a critical type in alignment padded structure layout such that all non-padding fields come before it without increasing structure size.
> 
> We split the problem into three cases. In all cases, our critical type is Tail(size A, align B), and our structure has alignment Q, which is assumed to be sufficiently aligned for all fields.
> 
> Case 1:
> 
> All other fields are before the tail.
> 
> The layout can be broken into four parts:
> 
> - Before(size X, align Y)
> - Padding to B
> - Tail(size A, align B)
> - Padding to Q
> 
> ```rust
> struct(size N1, align Q) {
> // align Q
> Before(size X, align Y)
> Padding(size X amod B)
> // align B
> Tail(size A, align B)
> Padding(size ((X ~ B) + A) amod Q)
> // align Q
> }
> 
> where
> N1 = ((X ~ B) + A) ~ Q)
> 
> ```
> 
> All non-padding fields are before the critical type, thus this layout already satisfies our desired condition.
> 
> Case 2:
> 
> All other fields are after the tail.
> 
> The layout can be broken into four parts:
> 
> - Tail(size A, align B)
> - Padding to Y
> - After(size X, align Y)
> - Padding to Q
> 
> ```struct
> struct(size N2, align Q) {
> // align Q
> Tail(size A, align B)
> Padding(size A amod Y)
> // align Y
> After(size X, align Y)
> Padding(size ((A ~ Y) + X) amod Q)
> // align Q
> }
> 
> where
> N2 = ((A ~ Y) + X) ~ Q
> 
> ```
> 
> By definition:  
> `B ≤ Q`.  
> `Q mod B = 0`.  
> `A mod B = 0`. `Y ≤ Q`.  
> `Q mod Y = 0`.  
> `X mod Y = 0`.  
> `N1 mod Q = 0`.  
> `N2 mod Q = 0`.
> 
> > **failure**
> >
> > We can convert this to the layout in case 1 by setting `Before(size X, align Y) = After(size X, align Y)`. We prove this does not increase the size.
> > 
> > Proof:
> > 
> > ```rust
> > N1 ≤ N2
> > ((X ~ B) + A) ~ Q) ≤ ((A ~ Y) + X) ~ Q)
> > let N'1 = (X ~ B) + A
> > = X + (X amod B) + A
> > let N'2 = (A ~ Y) + X
> > = A + (A amod Y) + X
> > N'1 ~ Q ≤ N'2 ~ Q
> > N'1 + (N'1 amod Q) ≤ N'2 + (N'2 amod Q)
> > (N'1 amod Q) - (N'2 amod Q) ≤ N'2 - N'1
> > (N'1 amod Q) - (N'2 amod Q) ≤ A + (A amod Y) + X - (X + (X amod B) + A)
> > (N'1 amod Q) - (N'2 amod Q) ≤ (A amod Y) - (X amod B)
> > ???
> > 
> > ```
> 
> > **failure**
> >
> > Reorder to
> > 
> > - After(size X, align Y)
> > - Padding(size ((A ~ Y) + X) amod Q)
> > - Tail(size A, align B)
> > - Padding(size A amod Y)
> > 
> > The overall size/align trivially stays the same, and we only need to prove that Tail is sufficiently aligned to B.
> > 
> > ```rust
> > (X + (((A ~ Y) + X) amod Q)) mod B = 0
> > ???
> > 
> > ```
> 
> Case 3:
> 
> There are fields before and after the tail.
> 
> The layout can be broken into six parts:
> 
> - Prior(size I, align J)
> - Padding to B
> - Tail(size A, align B)
> - Padding to V
> - Latter(size U, align V)
> - Padding to Q
> 
> Strategy: switch Prior/Tail along with padding to maybe reduce to case 2?

Fridge thought even though it's way too late to be doing formal proofs: I was assuming that the noncritical blobs also had a size multiple of alignment, and that's not necessarily the case. Additionally, a following field blob is not necessarily aligned to the maximum of its internal field allotments.

Even forgetting these things I got horribly stuck to not remembering how to do this kind of modular reasoning over multiple rings simultaneously — if I ever knew at that

---

<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: [June 24, 2022, 6:49am UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/15 "2022-06-24T06:49:35Z")

</div>

The main thing that needs to be provoked for a counterexample is an unsizable tail with padding after it (this occurs to pad to the whole structure alignment). The hard part is doing so with a structure where enough fields can be niched into that space to save an alignment size. The spare unused capacity after the unsizable tail is by definition capped at `align_of(Whole) - align_of(Tail)`, so to save an alignment size, some padding before the tail must exist to be able to combine with the trailing padding to make enough space to shrink the type.

---

<div class="post-metadata">

### Author: ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)
#### Post date: [June 24, 2022, 7:17am UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/16 "2022-06-24T07:17:26Z")

</div>

The unsizable field is always last. For structs the padding before the field can be easily calculated using a field offset and the alignment stored in the metadata. For enums it would require reading which variant is the current variant and matching on this. This is a lot more complex and means that taking the address of a field requires a read of the pointee, which may be invalid for raw pointers.

---

<div class="post-metadata">

### Author: ![quaternic](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quaternic/32/10440_2.png) [@quaternic](https://internals.rust-lang.org/u/quaternic)
#### Post date: [June 24, 2022, 9:15am UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/17 "2022-06-24T09:15:02Z")

</div>

> [@CAD97](#):
>
> The theorem to prove is that given any layout, you can construct a layout at least as good with the desired field in the unsizing location.

Assuming I understood the problem correctly, here's an algorithmic proof:

Suppose the type's alignment requirement is B.

for A in [1,2,4,...,B/4,B/2]:

1. Gather the fields with alignment A together.
2. If their total size is not a multiple of the next alignment (2A), add one A-byte padding element to fix that
3. Reorder these fields arbitrarily (they have the same alignment)
4. Replace these fields (including the possible padding element) with a single tuple with 2A-alignment (this will be included in step 1 on the next iteration)

When done you only have fields of the maximum alignment B, so no more padding is required. Total padding added is at most `1+2+4+...+B/4+B/2 = B-1` bytes, so it is minimal as the padded size must be a multiple of B. Any specific field can be made the last in the struct by doing so in every step 3. (You can get much more freedom in step 4 by pairing the fields into multiple chunks, each a multiple of 2A in size.)

---

<div class="post-metadata">

### Author: ![CraftSpider](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/craftspider/32/7551_2.png) [@CraftSpider](https://internals.rust-lang.org/u/CraftSpider)
#### Post date: [June 24, 2022, 2:59pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/18 "2022-06-24T14:59:36Z")

</div>

I'm not 100%, but I think that works? If the last field is unsize, we can always align it into last, and if not, we just don't care. And depending on when layout is decided, we may even be able to only do it when `Unsize` is implemented.

---

<div class="post-metadata">

### Author: ![CraftSpider](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/craftspider/32/7551_2.png) [@CraftSpider](https://internals.rust-lang.org/u/CraftSpider)
#### Post date: [June 24, 2022, 3:06pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/19 "2022-06-24T15:06:15Z")

</div>

I realized I didn't respond to the last thing, about 'future ideas' - I have vague ideas about some `#[metadata]` attribute or something, but I think your `DynSized` proposal would fulfill that requirement, and combined with this, may even entirely fulfill my usability desires.

---

<div class="post-metadata">

### Author: ![InfernoDeity](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/infernodeity/32/7588_2.png) [@InfernoDeity](https://internals.rust-lang.org/u/InfernoDeity)
#### Post date: [June 24, 2022, 10:45pm UTC](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861/20 "2022-06-24T22:45:46Z")

</div>

I'd note that in this case, it's entirely possible that `Object` and `SizedObject` use different layouts, and in particular: `fields` be at a different offset in `SizedObject` and `Object`. As a practical example, if `*const Field` was something with more alignment (say, a simd type), then then using alignment-sorting, `fields` would come before `name` in `SizedObject`, but not in `Object`. This change would effectively enjoin the compiler from ever reordering the last field of a structure relative to any other field, which can have significant impact on its ability to lay types out the most efficiently.

[Next page](https://internals.rust-lang.org/t/pre-rfc-improved-unsizing/16861.md?page=2)
