use std::{ mem::ManuallyDrop, ops::{Deref, DerefMut}, }; macro_rules! assert_size_eq { ($t:ty, $u:ty) => {{ struct AssertEqSize(std::marker::PhantomData, std::marker::PhantomData); impl AssertEqSize { const VAL: usize = { if std::mem::size_of::() != std::mem::size_of::() { panic!("Types have different size"); } 1 }; } let _ = AssertEqSize::<$t, $u>::VAL; }}; } macro_rules! assert_align_eq { ($t:ty, $u:ty) => {{ struct AssertEqAlign(std::marker::PhantomData, std::marker::PhantomData); impl AssertEqAlign { const VAL: usize = { if std::mem::align_of::() != std::mem::align_of::() { panic!("Types have different alignment"); } 1 }; } let _ = AssertEqAlign::<$t, $u>::VAL; }}; } pub struct VecStorage { ptr: *mut T, cap: usize, } impl Default for VecStorage { fn default() -> Self { let mut v = ManuallyDrop::new(vec![]); Self { ptr: v.as_mut_ptr(), cap: v.capacity(), } } } impl VecStorage { pub fn take<'a>(&'a mut self) -> RealizedVec<'a, T, T> { self.take_as() } pub fn take_as<'a, U>(&'a mut self) -> RealizedVec<'a, T, U> { assert_size_eq!(T, U); assert_align_eq!(T, U); unsafe { RealizedVec { vec: ManuallyDrop::new(self.to_vector()), storage: self, } } } unsafe fn to_vector(&mut self) -> Vec { unsafe { Vec::from_raw_parts(self.ptr as _, 0, self.cap) } } } impl Drop for VecStorage { fn drop(&mut self) { unsafe { drop(self.to_vector::()); } } } pub struct RealizedVec<'a, T, U> { vec: ManuallyDrop>, storage: &'a mut VecStorage, } impl<'a, T, U> Drop for RealizedVec<'a, T, U> { fn drop(&mut self) { self.vec.clear(); self.storage.ptr = self.vec.as_mut_ptr() as _; self.storage.cap = self.vec.capacity(); } } impl<'a, T, U> Deref for RealizedVec<'a, T, U> { type Target = Vec; fn deref(&self) -> &Self::Target { self.vec.deref() } } impl<'a, T, U> DerefMut for RealizedVec<'a, T, U> { fn deref_mut(&mut self) -> &mut Self::Target { self.vec.deref_mut() } }