use cxx::{memory::UniquePtrTarget, UniquePtr};
use moveit::MoveRef;
use std::{
marker::{PhantomData, PhantomPinned},
pin::Pin,
};
pub unsafe trait RValueParam<T>: Sized {
#[doc(hidden)]
fn get_ptr(stack: Pin<&mut Self>) -> *mut T;
}
unsafe impl<T> RValueParam<T> for UniquePtr<T>
where
T: UniquePtrTarget,
{
fn get_ptr(stack: Pin<&mut Self>) -> *mut T {
unsafe {
(Pin::into_inner_unchecked(
(*Pin::into_inner_unchecked(stack))
.as_mut()
.expect("Passed a NULL UniquePtr as a C++ rvalue parameter"),
)) as *mut T
}
}
}
unsafe impl<T> RValueParam<T> for Pin<Box<T>> {
fn get_ptr(stack: Pin<&mut Self>) -> *mut T {
unsafe {
(Pin::into_inner_unchecked((*Pin::into_inner_unchecked(stack)).as_mut())) as *mut T
}
}
}
unsafe impl<T> RValueParam<T> for Pin<MoveRef<'_, T>> {
fn get_ptr(stack: Pin<&mut Self>) -> *mut T {
unsafe {
(Pin::into_inner_unchecked((*Pin::into_inner_unchecked(stack)).as_mut())) as *mut T
}
}
}
#[doc(hidden)]
pub struct RValueParamHandler<T, RVP>
where
RVP: RValueParam<T>,
{
space: Option<RVP>,
_pinned: PhantomPinned,
_data: PhantomData<T>,
}
impl<T, RVP: RValueParam<T>> RValueParamHandler<T, RVP> {
pub unsafe fn populate(self: Pin<&mut Self>, param: RVP) {
*Pin::into_inner_unchecked(self.map_unchecked_mut(|s| &mut s.space)) = Some(param)
}
pub fn get_ptr(self: Pin<&mut Self>) -> *mut T {
unsafe {
RVP::get_ptr(Pin::new_unchecked(
self.get_unchecked_mut().space.as_mut().unwrap(),
))
}
}
}
impl<T, VP: RValueParam<T>> Default for RValueParamHandler<T, VP> {
fn default() -> Self {
Self {
space: None,
_pinned: PhantomPinned,
_data: PhantomData,
}
}
}