Is a Newtype Pattern Tuple Struct Have a Memory Layout Equivalent to It's Member?

I'm using the ulid crate and it's Ulid type is defined as struct Ulid(pub u128).

I'm trying to understand whether or not the default #[repr(Rust)] representation guarantees that the Ulid will have the same memory layout as a u128.

It seems like it's extremely likely to have the same layout, but is it possible that the Rust representation could add like a ghost offset to the u128 isn't it?

I'm wondering whether or not I need to open a PR to the ulid crate to see if they are fine adding a #[repr(transparent)] annotation to the struct.

There is no such guarantee in the default representation. Structures with one field are as undefined in layout as structures with any other number of fields.

6 Likes

The only time you'd need #[repr(transparent)] is when you need to cast between &u128 and &Ulid (or some other POD type), or when using the type in FFI interchangeably with the wrapped type (but u128 is an FFI nightmare). If you aren't doing those kinds of tricks, it's generally considered preferable to keep the standard layout. The compiler isn't going to just randomly decide to pick a bad layout (unless you ask it to, e.g. -Zrandomize-layout).

6 Likes

Yeah, I'm looking to be able to cast the Ulid unsafely to a u128 for a scripting-type integration.

Oh, really. What's the issue? I'm not exactly using it over FFI yet, since the language I'm going to be scripting with is written in Rust, but the idea would be to FFI friendly probably.

Maybe it'd be better to represent it with two u64s.


My current work-around was that I realized that if I validate that the Layout::new::<Ulid>().size == Layout::new::<u128>().size, then, according to the guarantees about the default representation, I'm pretty sure that we know that the layout is the same.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.