use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::AtomicBool;
use std::task::Context;
pub fn spawn<F: 'static + Future<Output = ()>>(future: F) {
let future_ptr = Box::into_raw(Box::new(future));
let future_ptr_ptr: *mut *mut dyn Future<Output = ()> = Box::into_raw(Box::new(future_ptr));
let mut pinned_future = unsafe { Pin::new_unchecked(&mut *future_ptr) };
if pinned_future
.as_mut()
.poll(&mut Context::from_waker(&waker::waker(
future_ptr_ptr as *const (),
)))
.is_ready()
{
unsafe {
let _ = Box::from_raw(future_ptr);
let _ = Box::from_raw(future_ptr_ptr);
}
}
}
pub(crate) static CLEANUP: AtomicBool = AtomicBool::new(false);
mod waker {
use super::*;
use std::{
sync::atomic::Ordering,
task::{RawWaker, RawWakerVTable, Waker},
};
type FuturePtr = *mut dyn Future<Output = ()>;
static MY_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
fn raw_waker(ptr: *const ()) -> RawWaker {
RawWaker::new(ptr, &MY_VTABLE)
}
fn clone(ptr: *const ()) -> RawWaker {
raw_waker(ptr)
}
unsafe fn wake(ptr: *const ()) {
let boxed_future_ptr_ptr = Box::from_raw(ptr as *mut FuturePtr);
let future_ptr: FuturePtr = *boxed_future_ptr_ptr;
let boxed_future = Box::from_raw(future_ptr);
let mut pinned_future = Pin::new_unchecked(&mut *future_ptr);
if !super::CLEANUP.load(Ordering::Relaxed)
&& pinned_future
.as_mut()
.poll(&mut Context::from_waker(&waker::waker(ptr)))
.is_pending()
{
Box::into_raw(boxed_future_ptr_ptr);
Box::into_raw(boxed_future);
}
}
fn wake_by_ref(_: *const ()) {}
fn drop(_: *const ()) {}
pub fn waker(ptr: *const ()) -> Waker {
unsafe { Waker::from_raw(raw_waker(ptr)) }
}
}