spawn_groups 1.1.0

Structured concurrency construct written in Rust, for Rustaceans
Documentation
use std::{
    future::Future,
    pin::Pin,
    ptr::NonNull,
    task::{Context, Poll},
};

pub(crate) struct Task<T> {
    poll_fn: fn(NonNull<()>, &mut Context<'_>) -> Poll<T>,
    drop_fn: fn(NonNull<()>),
    raw_ptr: NonNull<()>,
}

impl<T> Task<T> {
    pub(crate) fn new<Fut: Future<Output = T>>(fut: Fut) -> Self {
        unsafe {
            Self {
                raw_ptr: NonNull::new_unchecked(Box::into_raw(Box::new(fut)).cast()),
                poll_fn: |self_ptr, cntx| {
                    Pin::new_unchecked(self_ptr.cast::<Fut>().as_mut()).poll(cntx)
                },
                drop_fn: |raw_ptr| _ = Box::from_raw(raw_ptr.cast::<Fut>().as_ptr()),
            }
        }
    }

    pub(crate) fn from_ref<Fut: Future<Output = T>>(fut: &mut Fut) -> Self {
        unsafe {
            Self {
                raw_ptr: NonNull::new_unchecked(<*mut Fut>::cast::<()>(fut)),
                poll_fn: |self_ptr, cntx| {
                    Pin::new_unchecked(self_ptr.cast::<Fut>().as_mut()).poll(cntx)
                },
                drop_fn: |_| {},
            }
        }
    }

    pub(crate) fn poll_task(&self, cx: &mut Context<'_>) -> Poll<T> {
        (self.poll_fn)(self.raw_ptr, cx)
    }
}

impl<T> Unpin for Task<T> {}

impl<T> Future for Task<T> {
    type Output = T;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        self.poll_task(cx)
    }
}

impl<T> Drop for Task<T> {
    fn drop(&mut self) {
        (self.drop_fn)(self.raw_ptr)
    }
}