vuot 0.0.1

Run recursive async functions without overflowing the stack
Documentation
use std::cell::Cell;
use std::future::Future;
use std::pin::Pin;
use std::ptr::NonNull;
use std::task::{Context, Poll};

use crate::side_channel::SideChannelFuture;

pub(crate) struct Sender<T, Fut> {
    future: Fut,
    result: Cell<Option<T>>,
}

impl<T, Fut> Sender<T, Fut> {
    /// # Safety
    ///
    /// The result pointer must be written to a pointer that is valid for the
    /// type `Cell<Option<T>>` before this future is polled.
    pub unsafe fn new(future: Fut) -> Self {
        let result = Cell::new(None);
        Self { future, result }
    }
}

impl<T, Fut> Future for Sender<T, Fut>
where
    Fut: Future<Output = T>,
{
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // Safety: `self.future` is only ever accessed pinned.
        let future = unsafe { self.as_mut().map_unchecked_mut(|this| &mut this.future) };

        match future.poll(cx) {
            Poll::Pending => Poll::Pending,
            Poll::Ready(value) => {
                self.result.set(Some(value));
                Poll::Ready(())
            }
        }
    }
}

impl<T, Fut> SideChannelFuture for Sender<T, Fut>
where
    Fut: Future<Output = T>,
{
    unsafe fn get_result_pointer(&self) -> NonNull<Cell<Option<()>>> {
        let result = &self.result;

        // Safety: we're turning a normal mutable reference into a pointer, so
        // this is never null
        let ptr: NonNull<Cell<Option<T>>> =
            unsafe { NonNull::new_unchecked(result as *const _ as *mut _) };

        // Safety: it is up to the caller to transmute this back to the correct
        // pointer type before using it.
        let ptr: NonNull<Cell<Option<()>>> = unsafe { std::mem::transmute(ptr) };

        ptr
    }
}