# Auto-trait for stable layout types with no padding?

**URL:** https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339
**Category:** language design
**Created:** [February 15, 2024, 11:53pm UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339 "2024-02-15T23:53:36Z")
**Posts on this page:** 17
**Page:** 1

<div class="post-metadata">

### Author: ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)
#### Post date: [February 15, 2024, 11:53pm UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/1 "2024-02-15T23:53:36Z")

</div>

There's a fairly common pattern of casting structs to bytes, and it has (among others!) footguns of using `repr(Rust)` structs, tuples (undefined ABI), or types with padding.

`repr(Rust)` is an invisible default, so this mistake doesn't stand out. It's harder to notice _absence_ of something, like `repr(C)` or `repr(transparent)`.

Padding is also invisible, and sometimes tricky to spot, like padding at the end of struct caused by alignment. It's also hard to check when using nested structs or type aliases.

Libraries that try to make cast/transmute safer, like `bytemuck`, unfortunately can't prevent these footguns at all. Their trait requires `unsafe impl`, and the library must trust it as-is. It can't check if it any implementation is correct. Incorrectly implementing a `Pod` trait is unfortunately just as easy to get wrong as incorrectly implementing a cast to bytes yourself.

Could Rust help here with auto traits for `repr(C)`/`repr(transparent)`/`repr(packed)` and especially auto traits for no padding?

I thought there was a safe transmute project working on this, but it looks [**very dead**](https://github.com/rust-lang/project-safe-transmute).

---

<div class="post-metadata">

### Author: ![cg909](https://avatars.discourse-cdn.com/v4/letter/c/90ced4/32.png) [@cg909](https://internals.rust-lang.org/u/cg909)
#### Post date: [February 16, 2024, 1:44am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/2 "2024-02-16T01:44:29Z")

</div>

I'd like something like that too.

I only see two small problems:

1. An auto-trait for "no padding" is a semver hazard. Once a type without padding is in a public interface, adding anything to it that causes padding breaks foreign code that uses it with a trait bound on e.g. `NoPadding`.

2. All currently existing auto-traits are leaky, which can (again) cause semver hazards. For example

---

<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: [February 16, 2024, 1:45am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/3 "2024-02-16T01:45:49Z")

</div>

+2, at TigerBeetle we use `comptime assert(stdx.no_padding(T))` all over the place all the time, and it does prevent nasty bugs in pervasively zero-copy designs.

---

<div class="post-metadata">

### Author: ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)
#### Post date: [February 16, 2024, 2:52am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/4 "2024-02-16T02:52:09Z")

</div>

> [@kornel](#):
>
> and especially auto traits for no padding?

I don't think just an auto trait works for this, because `u8: NoPadding` and `u16: NoPadding` but `(u8, u16): !NoPadding`.

An auto trait works for `AnyBitPatternValid` or more limitedly `ZeroedIsValid`, but not for a lack of padding.

---

<div class="post-metadata">

### Author: ![cg909](https://avatars.discourse-cdn.com/v4/letter/c/90ced4/32.png) [@cg909](https://internals.rust-lang.org/u/cg909)
#### Post date: [February 16, 2024, 3:04am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/5 "2024-02-16T03:04:52Z")

</div>

Right, it would need to be a compiler-implemented marker trait like `Sized`, not an auto-trait.

---

<div class="post-metadata">

### Author: ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)
#### Post date: [February 16, 2024, 3:23am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/6 "2024-02-16T03:23:51Z")

</div>

> [@kornel](#):
>
> Their trait requires `unsafe impl`, and the library must trust it as-is. It can't check if it any implementation is correct. Incorrectly implementing a `Pod` trait is unfortunately just as easy to get wrong as incorrectly implementing a cast to bytes yourself.

[They have a `derive` macro for it.](https://docs.rs/bytemuck/latest/bytemuck/derive.Pod.html)

I'd also like to see some of these traits or similar `std`ized (and some reviving of safe transmute for that matter). I do think it should be opt-in, like `Copy`. Reusing an existing attribute like `repr(transparent)` runs into problems around ["this was an implementation detail, not a promise".](https://github.com/rust-lang/rust/pull/107680)

---

<div class="post-metadata">

### Author: ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)
#### Post date: [February 16, 2024, 1:12pm UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/7 "2024-02-16T13:12:31Z")

</div>

If all you need is to turn some struct into bytes wouldn't a `freeze` be sufficient?

---

<div class="post-metadata">

### Author: ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)
#### Post date: [February 16, 2024, 3:36pm UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/8 "2024-02-16T15:36:57Z")

</div>

> [@scottmcm](#):
>
> I don't think just an auto trait works for this `(u8, u16): !NoPadding`.

I assume it would need some magic from the compiler (_as if_ the padding was a field with `!NoPadding`).

> [@the8472](#):
>
> If all you need is to turn some struct into bytes wouldn't a `freeze` be sufficient?

Depends on the context, but I think generally no. If the padding is unexpected, it's a bug. It may mean that the exposed data layout doesn't match its spec.

---

<div class="post-metadata">

### Author: ![jack](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jack/32/3724_2.png) [@jack](https://internals.rust-lang.org/u/jack)
#### Post date: [February 16, 2024, 4:00pm UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/9 "2024-02-16T16:00:11Z")

</div>

Hi! I'm the person working on project safe transmute. I'm happy to say it's very much _not dead_ — in fact, working on safe transmutation is now my full-time job! We also have an [experimental safe transmute trait](https://doc.rust-lang.org/stable/core/mem/trait.BikeshedIntrinsicFrom.html) landed in the compiler!

That said, at the moment, most of the experimentation is happening outside of the standard library. We're iterating on what the right API is, and scraping the defined limits of Rust's memory model. This API iteration work is happening in the [zerocopy](https://github.com/google/zerocopy) crate and relevant discussions about Rust's memory model are happening in the Unsafe Code Guidelines repo ([here's a sampler](https://github.com/rust-lang/unsafe-code-guidelines/issues?q=is%3Aissue+author%3Ajoshlf+)).

Right now, we're sprinting on nailing down fallible transmutation and support for unsized types. Soon, I'll be shifting focus back on the compiler-supported analysis to implement support for lifetime checking and revising our safety analysis.

I want to touch on this:

> [@kornel](#):
>
> Libraries that try to make cast/transmute safer, like `bytemuck`, unfortunately can't prevent these footguns at all. Their trait requires `unsafe impl`, and the library must trust it as-is. It can't check if it any implementation is correct. Incorrectly implementing a `Pod` trait is unfortunately just as easy to get wrong as incorrectly implementing a cast to bytes yourself.

I can't speak to bytemuck, but you might be pleasantly surprised by zerocopy. Our [`AsBytes`](https://docs.rs/zerocopy/latest/zerocopy/trait.AsBytes.html) trait comes with a [fairly sophisticated derive](https://docs.rs/zerocopy/latest/zerocopy/derive.AsBytes.html) that statically ensures both that the type has no uninitialized bytes, and that the bytes of the type have no provenance. Using `zerocopy` is _way_ easier than implementing byte casts correctly yourself.

---

<div class="post-metadata">

### Author: ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)
#### Post date: [February 16, 2024, 6:50pm UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/10 "2024-02-16T18:50:54Z")

</div>

> [@jack](#):
>
> it's very much _not dead_

Good to hear. Please update the repo, because “last updated 4 years ago” all over it doesn’t look like any work has been done, and that repo is linked from the official announcement of the wg creation.

---

<div class="post-metadata">

### Author: ![jjpe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jjpe/32/9779_2.png) [@jjpe](https://internals.rust-lang.org/u/jjpe)
#### Post date: [February 24, 2024, 12:02am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/12 "2024-02-24T00:02:17Z")

</div>

**NOT A CONTRIBUTION**

> [@kornel](#):
>
> There's a fairly common pattern of casting structs to bytes

I've been searching for a way to do this with structs/enums that have components on the heap, and also the other way around i.e load such structs from bytesequences. I understand it's even less safe than going bungee jumping without a cord, but I'd like to look into it anyway. Where can I find more info on how to accomplish that with the current state-of-the-art?

EDIT: I'm looking into zerocopy, but an answer to my original question above would still be very much appreciated.

---

<div class="post-metadata">

### Author: ![Vorpal](https://avatars.discourse-cdn.com/v4/letter/v/aca169/32.png) [@Vorpal](https://internals.rust-lang.org/u/Vorpal)
#### Post date: [February 24, 2024, 12:15am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/13 "2024-02-24T00:15:32Z")

</div>

> [@jjpe](#):
>
> **NOT A CONTRIBUTION**

Okay, I'll bite. What is that about? I have seen a couple of people use that.

Now to (attempt to) answer your actual question: there is zerocopy as you already found. Bytemuck is another crate for similar things.

I believe there are a couple of relevant zero copy deserialisation crates too. [GitHub - djkoloski/rust\_serialization\_benchmark: Benchmarks for rust serialization frameworks](https://github.com/djkoloski/rust_serialization_benchmark) has some benchmarks. Some of those are zero copy. Maybe you can take inspiration from whatever they are doing (or avoid it, I belive abomonation in particular is very very unsound).

---

<div class="post-metadata">

### Author: ![jjpe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jjpe/32/9779_2.png) [@jjpe](https://internals.rust-lang.org/u/jjpe)
#### Post date: [February 24, 2024, 12:21am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/14 "2024-02-24T00:21:40Z")

</div>

> [@Vorpal](#):
>
> Okay, I'll bite. What is that about? I have seen a couple of people use that.

The way I interpret it is mostly as a marker for people who only want to "follow the thread" that they needn't waste their time reading such a reply.

> [@Vorpal](#):
>
> Now to (attempt to) answer your actual question: there is zerocopy as you already found. Bytemuck is another crate for similar things.

The main issue with both of them is that I haven't seen any support for heap storage (i.e. `Box<T>`), which is essential for my use case. If that support does exist, I'd be happy to be corrected; but for example the docs for zerocopy list no `FromBytes` impl for `Vec<T>`. The other direction isn't such an issue because `Vec<T>` can deref to a slice, which [does](https://docs.rs/zerocopy/latest/zerocopy/trait.AsBytes.html#impl-AsBytes-for-%5BT%5D) have an impl listing for `AsBytes`.

A nice to have would be support for other collections, eg BTreeMap/Set. HashMap/Set would also be nice but without support for ordering that could potentially get awkward quickly.

---

<div class="post-metadata">

### Author: ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)
#### Post date: [February 24, 2024, 12:36am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/15 "2024-02-24T00:36:30Z")

</div>

I generally assume such disclaimers are something some people are required to include on their posts due to their employment contract or the like.

---

<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: [February 24, 2024, 1:29am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/16 "2024-02-24T01:29:38Z")

</div>

[designated in writing by the copyright owner as "Not a Contribution."](https://github.com/rust-lang/rust/blob/1623634aa5ccc7ce7390368f308e2cf93c8a2587/LICENSE-APACHE#L60)

---

<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: [February 24, 2024, 1:34am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/17 "2024-02-24T01:34:39Z")

</div>

> [@jjpe](#):
>
> I've been searching for a way to do this with structs/enums that have components on the heap,

It's impossible for _actual_ heap usage, but the [zerovec](https://crates.io/crates/zerovec) crate is designed to support truly zero copy deserialization of immutable variable size collections. Generally the approach requires `Cow`-like functionality, where any mutation of the collection switches back to the usual heap representation.

---

<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: [May 24, 2024, 1:35am UTC](https://internals.rust-lang.org/t/auto-trait-for-stable-layout-types-with-no-padding/20339/18 "2024-05-24T01:35:00Z")

</div>

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