use std::{
mem::{
size_of,
align_of,
transmute,
transmute_copy,
ManuallyDrop,
},
ptr::{
drop_in_place,
slice_from_raw_parts_mut,
},
marker::Unsize,
};
pub unsafe trait HeteroSizedPush<T: ?Sized> {
unsafe fn elem_size(&self) -> usize;
unsafe fn elem_align(&self) -> usize;
unsafe fn elem_ptr(&self) -> *const T;
unsafe fn elem_drop_handler(&self) -> fn(*mut u8, usize);
unsafe fn outer_drop(&mut self);
}
pub struct InPlace<E>(pub E);
unsafe impl<T: ?Sized, E: Unsize<T>> HeteroSizedPush<T> for InPlace<E> {
unsafe fn elem_size(&self) -> usize {
size_of::<E>()
}
unsafe fn elem_align(&self) -> usize {
align_of::<E>()
}
unsafe fn elem_ptr(&self) -> *const T {
&self.0 as &T as *const T
}
unsafe fn elem_drop_handler(&self) -> fn(*mut u8, usize) {
|data, _| {
drop_in_place(transmute::<
*mut u8,
&mut E,
>(data));
}
}
unsafe fn outer_drop(&mut self) {}
}
unsafe impl<'a, I: Copy> HeteroSizedPush<[I]> for &'a [I] {
unsafe fn elem_size(&self) -> usize {
self.len() * size_of::<I>()
}
unsafe fn elem_align(&self) -> usize {
align_of::<I>()
}
unsafe fn elem_ptr(&self) -> *const [I] {
*self as *const [I]
}
unsafe fn elem_drop_handler(&self) -> fn(*mut u8, usize) {
|_, _| () }
unsafe fn outer_drop(&mut self) {}
}
unsafe impl<I> HeteroSizedPush<[I]> for Vec<I> {
unsafe fn elem_size(&self) -> usize {
self.len() * size_of::<I>()
}
unsafe fn elem_align(&self) -> usize {
align_of::<I>()
}
unsafe fn elem_ptr(&self) -> *const [I] {
self.as_slice() as *const [I]
}
unsafe fn elem_drop_handler(&self) -> fn(*mut u8, usize) {
|start, len| {
let elems: &mut [I] = &mut *slice_from_raw_parts_mut(
start as *mut I,
len,
);
for elem in elems {
drop_in_place(elem);
}
}
}
unsafe fn outer_drop(&mut self) {
drop(transmute_copy::<
Vec<I>,
Vec<ManuallyDrop<I>>,
>);
}
}
unsafe impl<'a> HeteroSizedPush<str> for &'a str {
unsafe fn elem_size(&self) -> usize {
(*self).len()
}
unsafe fn elem_align(&self) -> usize {
1
}
unsafe fn elem_ptr(&self) -> *const str {
*self as *const str
}
unsafe fn elem_drop_handler(&self) -> fn(*mut u8, usize) {
|_, _| () }
unsafe fn outer_drop(&mut self) {}
}
unsafe impl<T: ?Sized> HeteroSizedPush<T> for Box<dyn HeteroSizedPush<T>> {
unsafe fn elem_size(&self) -> usize {
Box::as_ref(self).elem_size()
}
unsafe fn elem_align(&self) -> usize {
Box::as_ref(self).elem_align()
}
unsafe fn elem_ptr(&self) -> *const T {
Box::as_ref(self).elem_ptr()
}
unsafe fn elem_drop_handler(&self) -> fn(*mut u8, usize) {
Box::as_ref(self).elem_drop_handler()
}
unsafe fn outer_drop(&mut self) {
drop(transmute_copy::<
Box<dyn HeteroSizedPush<T>>,
Box<ManuallyDrop<dyn HeteroSizedPush<T>>>,
>(self));
}
}