Closed
Description
enum WithBox {
Sized(Box<Sized>),
Unsized(Box<Unsized>),
}
enum WithUnitPtr {
Sized( /* 0usize */ ptr::NonNull<()>),
Unsized(ptr::NonNull<()>, usize ),
}
fn main() {
dbg!(size_of::<WithBox>()); // = 24
dbg!(size_of::<WithUnitPtr>()); // = 24
dbg!(size_of::<ManuallyNiched>()); // = 16
}
struct ManuallyNiched {
a: usize,
b: usize,
}
impl From<WithBox> for ManuallyNiched {
fn from(this: WithBox) -> ManuallyNiched {
match this {
WithBox::Sized(this) => ManuallyNiched {
a: 0,
b: Box::into_raw(this) as usize,
},
WithBox::Unsized(this) => ManuallyNiched {
b: this.len(),
a: Box::into_raw(this) as *mut Sized as usize,
},
}
}
}
impl From<ManuallyNiched> for WithBox {
fn from(this: ManuallyNiched) -> WithBox {
unsafe {
match this.a {
0 => WithBox::Sized(Box::from_raw(this.b as *mut _)),
_ => WithBox::Unsized(Box::from_raw(slice::from_raw_parts_mut(
this.a as *mut _,
this.b,
))),
}
}
}
}
Specifically, the tagged union of ptr::NonNull<{Sized type}>
and ptr::NonNull<{!Sized type}>
can niche together to be the size of ptr::NonNull<{!Sized type}>
(for unsized types with non-zero sized metadata) by storing the discriminant for the sized pointer in the 0 niche of the non-null pointer to the unsized type (and the pointer to the sized type in the pointer metadata of the unsized type).