New `Layout::with_metadata` method?

The std::alloc::Layout type currently has a new constructor for Sized types, and an array constructor for slices. There is no direct way to create Layout for other DSTs.

With nightly Rust, you can create DST layouts but in a roundabout way. The for_value_raw constructor (feature layout_for_ptr) takes a maybe-fat pointer, and you can in turn construct this pointer with ptr::from_raw_parts (feature ptr_metadata). You're creating a dummy pointer, only to throw away its address and use just the metadata. Why not short-circuit that process?

So I propose adding the following constructor method to Layout:

pub fn with_metadata<T>(metadata: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
where
    T: ?Sized

For slices, the Metadata is just a usize, so this would be a more generic replacement for Layout::array. In theory, once it's all stabilised, that constructor would be redundant to this new one.

This obviously depends on the ptr_metadata feature, and implementing it may also depend on layout_for_ptr. I don't know what the process is for feature dependencies like that. Also, I'm still pretty unfamiliar with the proposal process in general, so if anyone has advice for how to proceed with making this "formal" I'd appreciate it!

2 Likes

I'd prefer a function of this shape myself. (And for some context, I'm the one who added the layout_for_ptr functions.) The issue is that, despite it being possible for all current type kinds, we can't guarantee that getting the pointee layout from just the pointer metadata is possible for all potentially supported future type kinds.

Consider a type like a thin CStr. In order to get the size of a value, it's required to call strlen and count the bytes in the value until the terminating nul byte. This obviously isn't possible if you only have the unit metadata and not a valid pointer.

T-lang have signed off on that, given a (value of a) type has a knowable size, it's guaranteed possible to get that size using a valid pointer to the potentially dropped value. (This is required when dropping a Weak<T>.) To expose anything further would require T-lang signoff on the newly provided guarantees.

1 Like

One awkward thing is that ptr::slice_from_raw_parts means that even with the full pointer we'll end up wanting both a safe -> Result<Layout, LayoutError> version and an unsafe -> Layout one in practise (even for simple things like slices) because something like Vec wants to get mul nuw nsw in the codegen and no check, but a safe function on metadata can't.

1 Like

Is that not already an issue for Layout::for_value_raw then?

Good point. I've been looking into this myself, and it seems that the issue comes down to two compiler intrinsics for size and alignment, that aren't safe to call. I also don't see a way to make them safe to call for arbitrary metadata.

That's a bit of a bummer, because future things like Box would like to be able to rely on safely creating a Layout. Box::try_new_uninit_slice already does this for slices using Layout::array, and it would be nice to have support for custom DSTs too.