{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreibuoi6fg7xvr35rpe5gh2vuzrx3esfrbaz42ztrdmrm7sfn3tjbnm",
"uri": "at://did:plc:ivbknywyskln22er3nkssdhl/app.bsky.feed.post/3ml5cbwsun3b2"
},
"path": "/t/std-phantomunsized-marker-type/24219#post_5",
"publishedAt": "2026-05-05T21:26:00.000Z",
"site": "https://internals.rust-lang.org",
"textContent": "As an extension, `PhantomUnsized` could gain a type parameter specifying the pointer metadata. The type must be `Copy` and have the same layout as `usize` (for now, assuming the compiler can't take types larger/smaller than `usize`).\n\nFor example you could define your own 2D plane type:\n\n\n // NOTE: This would not be compatible with the current `usize` restriction.\n // However, I'm assuming this restriction would exist because the compiler\n // assumes pointer metadata has the same layout as a pointer.\n #[derive(Copy)]\n struct PlaneMeta {\n width: u32,\n height: u32,\n }\n\n struct Plane<T> {\n // Stride is stored in the Plane header because it is the same across all\n // pointers/references.\n stride: u32,\n // :)\n _align_hack: [T; 0],\n _phantom: PhantomData<T>,\n _unsized: PhantomUnsized<PlaneMeta>,\n }\n\n // `&Plane<u8>` now works as a 2D slice. This can also be extended to any\n // number of dimensions.\n\n\nLibraries could opt in to `MetaSized` with a new trait `PointerLayout` (probably under `std::ops`).\n\n**NOTE** : I'm not sure if this should be implemented on the pointer metadata or the pointee.\n\n**NOTE 2** : `size_of_val_raw` may not interact with this well as `PointerLayout` implementations can assume their pointers are dereferenceable. However the docs say that \"this function is only safe to call\" if the metadata is from a slice or trait object. _For now_ I've added a const generic arg specifying whether the call is from `*_of_val` (using references) or `*_of_val_raw` (using ptrs).\n\nin `main/library/core/src/ops/mod.rs`:\n\n\n pub trait std::ops::PointerLayout<T: Pointee<Metadata = Self>> {\n unsafe fn layout_of<const RAW: bool>(ptr: *const T) -> Layout;\n }\n\n\n\n // This implementation makes `Plane<T>` `MetaSized`.\n impl<T> std::ops::PointerLayout<Plane<T>> for PlaneMeta {\n unsafe fn layout_of<const RAW: bool>(ptr: *const Plane<T>) -> Layout {\n // Panicking is free because of the const generic, but implementations do not\n // have to panic because `*_of_val_raw` is allowed to invoke UB.\n if RAW {\n panic!(\"plane ptrs are not supported: pointer must be deref to compute\");\n }\n let stride = unsafe { (&raw const (*ptr).stride).read() };\n let meta = std::ptr::metadata(ptr);\n // It is undefined behavior to construct invalid planes with sizes that\n // overflow `usize` so we are allowed to invoke UB \"for speed\".\n let trailing_len = (stride as usize).unchecked_mul(meta.height as usize);\n unsafe {\n try {\n Layout::new_minimum::<Plane<T>>()\n .extend(Layout::new::<T>().repeat(trailing_len)?)?.0\n }\n .unwrap_unchecked()\n }\n }\n }\n\n\nThis would then allow for creating boxed planes (with some unsafe code):\n\n\n pub fn new_boxed(width: u32, height: u32, item: T) -> Box<Self>\n where T: Copy\n {\n let Some(trailing_len) = (width as usize).checked_mul(height as usize) else {\n panic!(\"plane is too large to allocate ({width}x{height})\")\n };\n let offset;\n let Ok(layout) = try {\n let layout;\n (layout, offset) = Layout::new_minimum::<Plane<T>>()\n .extend(Layout::new::<T>().repeat(trailing_len)?)?;\n layout.pad_to_align()?\n } else {\n panic!(\"plane is too large to allocate ({width}x{height})\")\n };\n\n // Assume `Box::new_uninit_unsized_layout` exists (I wish it did :( )\n let mut this = Box::new_uninit_unsized_layout::<Self>(\n layout,\n // Metadata needs to be passed when creating unsized types.\n // Alternatively this could always return `Box<[MaybeUninit<u8>]>`.\n PlaneMeta { width, height }\n );\n unsafe {\n (&raw mut (*this.as_ptr()).stride).write(width);\n }\n let items = unsafe {\n std::slice::slice_from_raw_parts_mut(\n this.as_ptr()\n .byte_add(offset)\n .cast::<MaybeUninit<T>>(),\n trailing_len,\n )\n };\n items.fill(MaybeUninit::new(item));\n this.assume_init()\n }\n\n\nI've omitted the `Drop` impl for `Plane`. It is trivial to write (it just drops all elements in place).",
"title": "`std::marker::PhantomUnsized` marker type"
}