#![allow(clippy::undocumented_unsafe_blocks)]
use futures::channel::oneshot::channel;
use futures::channel::oneshot::Receiver;
use futures::FutureExt;
use std::future::Future;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
#[derive(Default)]
pub struct Runtime {
tasks: Vec<Pin<Box<dyn Future<Output = ()> + 'static + Send>>>,
allocation: Vec<Pin<Box<dyn Future<Output = ()> + 'static + Send>>>,
}
pub(crate) mod waker {
use std::task::RawWaker;
use std::task::RawWakerVTable;
use std::task::Waker;
unsafe fn clone(_: *const ()) -> RawWaker {
RAW_WAKER
}
unsafe fn wake(_: *const ()) {}
unsafe fn wake_by_ref(_: *const ()) {}
unsafe fn drop(_: *const ()) {}
const VTABLE: &RawWakerVTable = &RawWakerVTable::new(clone, wake, wake_by_ref, drop);
const RAW_WAKER: RawWaker = RawWaker::new(std::ptr::null(), VTABLE);
pub fn waker() -> Waker {
unsafe { Waker::from_raw(RAW_WAKER) }
}
}
impl Runtime {
pub fn new() -> Self {
Default::default()
}
pub fn poll(&mut self) {
let waker = waker::waker();
let mut context = Context::from_waker(&waker);
let unfinished_futures = self.tasks.drain(..).filter_map(|mut future| {
match future.as_mut().poll(&mut context) {
Poll::Ready(_) => None,
Poll::Pending => Some(future),
}
});
self.allocation.extend(unfinished_futures);
std::mem::swap(&mut self.tasks, &mut self.allocation);
}
pub fn spawn<T: Send + 'static>(
&mut self,
future: impl Future<Output = T> + 'static + Send,
) -> Receiver<T> {
let (tx, rx) = channel();
let task = async move {
let r = future.await;
let _ = tx.send(r);
};
self.tasks.push(task.boxed());
rx
}
pub fn block_on<T>(&mut self, mut future: impl Future<Output = T>) -> T {
let waker = waker::waker();
let mut context = Context::from_waker(&waker);
let mut pinned_future = unsafe { Pin::new_unchecked(&mut future) };
loop {
if let Poll::Ready(result) = pinned_future.as_mut().poll(&mut context) {
return result;
}
self.poll();
}
}
}