use std::mem::MaybeUninit;
use std::pin::Pin;
use cxx::memory::UniquePtrTarget;
use cxx::UniquePtr;
use crate::slot::DroppingSlot;
use crate::DerefMove;
use crate::EmplaceUnpinned;
use crate::MoveRef;
use crate::TryNew;
pub unsafe trait MakeCppStorage: Sized {
unsafe fn allocate_uninitialized_cpp_storage() -> *mut Self;
unsafe fn free_uninitialized_cpp_storage(ptr: *mut Self);
}
impl<T: MakeCppStorage + UniquePtrTarget> EmplaceUnpinned<T> for UniquePtr<T> {
fn try_emplace<N: TryNew<Output = T>>(n: N) -> Result<Self, N::Error> {
unsafe {
let uninit_ptr = T::allocate_uninitialized_cpp_storage();
let uninit =
Pin::new_unchecked(&mut *(uninit_ptr as *mut MaybeUninit<T>));
let result = n.try_new(uninit);
if let Err(err) = result {
T::free_uninitialized_cpp_storage(uninit_ptr);
return Err(err);
}
Ok(UniquePtr::from_raw(uninit_ptr))
}
}
}
#[doc(hidden)]
pub struct DeallocateSpaceGuard<T: MakeCppStorage>(*mut T);
impl<T: MakeCppStorage> DeallocateSpaceGuard<T> {
fn assume_init_mut(&mut self) -> &mut T {
unsafe { &mut *self.0 }
}
}
impl<T: MakeCppStorage> Drop for DeallocateSpaceGuard<T> {
fn drop(&mut self) {
unsafe { T::free_uninitialized_cpp_storage(self.0) };
}
}
unsafe impl<T: MakeCppStorage + UniquePtrTarget> DerefMove for UniquePtr<T> {
type Storage = DeallocateSpaceGuard<T>;
#[inline]
fn deref_move<'frame>(
self,
storage: DroppingSlot<'frame, Self::Storage>,
) -> MoveRef<'frame, Self::Target>
where
Self: 'frame,
{
let cast = DeallocateSpaceGuard(self.into_raw());
let (storage, drop_flag) = storage.put(cast);
unsafe { MoveRef::new_unchecked(storage.assume_init_mut(), drop_flag) }
}
}