use std::{
future::Future,
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]
fn new(inner: NonNull<u8>) -> Self {
Self { inner }
}
}
unsafe impl Send for SendPtr {}
pub(crate) struct WriteOutput<F, T> {
future: F,
output_ptr: NonNull<T>,
success: bool,
}
unsafe impl<F, T> Send for WriteOutput<F, T> {}
impl<'scope, F, T> WriteOutput<F, T>
where
F: Future<Output = T> + Send + 'scope,
T: 'scope,
{
#[inline]
pub fn new(future: F, output_ptr: NonNull<T>) -> 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<F, T> Future for WriteOutput<F, T>
where
F: Future<Output = T>,
{
type Output = SendPtr;
#[inline]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<SendPtr> {
let this = unsafe { self.get_unchecked_mut() };
let fut = unsafe { Pin::new_unchecked(&mut this.future) };
let output = ready!(fut.poll(cx));
unsafe { this.output_ptr.write(output) };
this.success = true;
Poll::Ready(SendPtr::new(this.output_ptr.cast()))
}
}
impl<F, T> Drop for WriteOutput<F, T> {
#[inline]
fn drop(&mut self) {
if !self.success {
unsafe { drop(Box::from_raw(self.output_ptr.as_ptr())) };
}
}
}