What I was talking about with creating wide pointers
There are really no way to create a fat pointer to a user-defined structure, they can only be created by the compiler itself.
There's a way to create a wide pointer to a user-defined structure that is robust in the face of unspecified layouts: casting pointers with the same metadata.
Type of e
U
Cast performed by e as U
*T
*V
whereV: Sized
Pointer to pointer cast
or
T
andV
are compatible unsized types, e.g., both slices, both the same trait object.
And in particular, for slices and DSTs using slices:
For slice types like
[T]
and[U]
, the raw pointer types*const [T]
,*mut [T]
,*const [U]
, and*mut [U]
encode the number of elements in this slice. Casts between these raw pointer types preserve the number of elements. Note that, as a consequence, such casts do not necessarily preserve the size of the pointer's referent (e.g., casting*const [u16]
to*const [u8]
will result in a raw pointer which refers to an object of half the size of the original). The same holds forstr
and any compound type whose unsized tail is a slice type, such as structFoo(i32, [u8])
or(u64, Foo)
.
Additionally, for slices, core
gives us ptr::slice_from_raw_parts_mut
, so we can create slice pointers in particular without having to maintain the invariants of references, on stable today.
How to make use of it
We want to first construct a *mut [MaybeUninit<T>]
with the proper metadata (buffer capacity), but with the data address portion of the wide pointer pointing at the containing struct
. Then you can perform a pointer cast to get a *mut VecView<T>
with the appropriate metadata and data address.
Your Vec
and VecView
[1] have the same layout modulo the latter being unsized (alignment and field offsets). So the data address of the desired slice wide pointer can be the same as the original (data) pointer address (*mut Vec<T, N>
).
slice_from_raw_parts_mut
takes a *mut T
to construct a *mut [T]
, and the metadata (buffer capacity) is N
, so that would be:
let data = self as *mut Self as *mut MaybeUninit<T>;
let vv: *mut [MaybeUninit<T>] = slice_from_raw_parts_mut(data, N);
And then the pointer cast (and then borrowing as &mut
):
unsafe { &mut *(vv as *mut VecView<T>) }
And... that's it really.
However
You do miss out on the coercion goodness, so I'm guessing this is just a factual correction to your article and not a direction you want to pursue further.