use std::{
future::Future,
mem::MaybeUninit,
ops::Deref,
pin::Pin,
ptr::NonNull,
task::{ready, Context, Poll},
};
#[repr(transparent)]
pub(crate) struct SendPtr {
inner: NonNull<u8>,
}
impl Deref for SendPtr {
type Target = NonNull<u8>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl SendPtr {
#[inline]
unsafe fn new(inner: NonNull<u8>) -> Self {
Self { inner }
}
}
unsafe impl Send for SendPtr {}
pub(crate) struct WriteOutput<FutureType, TaskOutput> {
future: FutureType,
output_ptr: NonNull<MaybeUninit<TaskOutput>>,
success: bool,
}
unsafe impl<FutureType, TaskOutput> Send for WriteOutput<FutureType, TaskOutput> {}
impl<'scope, FutureType, TaskOutput> WriteOutput<FutureType, TaskOutput>
where
FutureType: Future<Output = TaskOutput> + Send + 'scope,
TaskOutput: 'scope,
{
#[inline]
pub(crate) unsafe fn new(future: FutureType, output_ptr: NonNull<MaybeUninit<TaskOutput>>) -> Self {
Self {
future,
output_ptr,
success: false,
}
}
#[inline]
pub unsafe fn into_static(self) -> Pin<Box<dyn Future<Output = SendPtr> + Send>> {
unsafe {
std::mem::transmute::<
Pin<Box<dyn Future<Output = SendPtr> + Send + 'scope>>,
Pin<Box<dyn Future<Output = SendPtr> + Send + 'static>>,
>(Box::pin(self))
}
}
}
impl<FutureType, TaskOutput> Future for WriteOutput<FutureType, TaskOutput>
where
FutureType: Future<Output = TaskOutput>,
{
type Output = SendPtr;
#[inline]
fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<SendPtr> {
let this = unsafe { self.get_unchecked_mut() };
let future_pinned = unsafe { Pin::new_unchecked(&mut this.future) };
let output = ready!(future_pinned.poll(context));
unsafe { this.output_ptr.as_mut().write(output) };
this.success = true;
Poll::Ready(unsafe { SendPtr::new(this.output_ptr.cast()) })
}
}
impl<FutureType, TaskOutput> Drop for WriteOutput<FutureType, TaskOutput> {
#[inline]
fn drop(&mut self) {
if !self.success {
unsafe { drop(Box::from_raw(self.output_ptr.as_ptr())) };
}
}
}