#[cfg(not(feature = "tokio"))]
use async_executor::Executor as AsyncExecutor;
#[cfg(not(feature = "tokio"))]
use async_task::Task as AsyncTask;
#[cfg(not(feature = "tokio"))]
use std::sync::Arc;
#[cfg(feature = "tokio")]
use std::{future::pending, marker::PhantomData};
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
#[cfg(feature = "tokio")]
use tokio::task::JoinHandle;
#[cfg(not(feature = "tokio"))]
#[derive(Debug, Clone)]
pub struct Executor<'a> {
executor: Arc<AsyncExecutor<'a>>,
}
#[cfg(feature = "tokio")]
#[derive(Debug, Clone)]
pub struct Executor<'a> {
phantom: PhantomData<&'a ()>,
}
impl<'a> Executor<'a> {
#[doc(hidden)]
pub fn spawn<T: Send + 'static>(
&self,
future: impl Future<Output = T> + Send + 'static,
#[allow(unused)] name: &str,
) -> Task<T> {
#[cfg(not(feature = "tokio"))]
{
Task(Some(self.executor.spawn(future)))
}
#[cfg(feature = "tokio")]
{
#[cfg(tokio_unstable)]
{
Task(Some(
tokio::task::Builder::new()
.name(name)
.spawn(future)
.unwrap(),
))
}
#[cfg(not(tokio_unstable))]
{
Task(Some(tokio::task::spawn(future)))
}
}
}
pub fn is_empty(&self) -> bool {
#[cfg(not(feature = "tokio"))]
{
self.executor.is_empty()
}
#[cfg(feature = "tokio")]
true
}
pub async fn tick(&self) {
#[cfg(not(feature = "tokio"))]
{
self.executor.tick().await
}
#[cfg(feature = "tokio")]
{
pending().await
}
}
pub(crate) fn new() -> Self {
#[cfg(not(feature = "tokio"))]
{
Self {
executor: Arc::new(AsyncExecutor::new()),
}
}
#[cfg(feature = "tokio")]
{
Self {
phantom: PhantomData,
}
}
}
pub(crate) async fn run<T>(&self, future: impl Future<Output = T>) -> T {
#[cfg(not(feature = "tokio"))]
{
self.executor.run(future).await
}
#[cfg(feature = "tokio")]
{
future.await
}
}
}
#[cfg(not(feature = "tokio"))]
#[doc(hidden)]
#[derive(Debug)]
pub struct Task<T>(Option<AsyncTask<T>>);
#[cfg(feature = "tokio")]
#[doc(hidden)]
#[derive(Debug)]
pub struct Task<T>(Option<JoinHandle<T>>);
impl<T> Task<T> {
#[allow(unused_mut)]
pub(crate) fn detach(mut self) {
#[cfg(not(feature = "tokio"))]
{
self.0.take().expect("async_task::Task is none").detach()
}
#[cfg(feature = "tokio")]
{
self.0.take().expect("tokio::task::JoinHandle is none");
}
}
}
impl<T> Task<T>
where
T: Send + 'static,
{
#[allow(unused)]
pub(crate) fn spawn_blocking<F>(f: F, #[allow(unused)] name: &str) -> Self
where
F: FnOnce() -> T + Send + 'static,
{
#[cfg(not(feature = "tokio"))]
{
Self(Some(blocking::unblock(f)))
}
#[cfg(feature = "tokio")]
{
#[cfg(tokio_unstable)]
{
Self(Some(
tokio::task::Builder::new()
.name(name)
.spawn_blocking(f)
.unwrap(),
))
}
#[cfg(not(tokio_unstable))]
{
Self(Some(tokio::task::spawn_blocking(f)))
}
}
}
}
impl<T> Drop for Task<T> {
fn drop(&mut self) {
#[cfg(feature = "tokio")]
{
if let Some(join_handle) = self.0.take() {
join_handle.abort();
}
}
}
}
impl<T> Future for Task<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
#[cfg(not(feature = "tokio"))]
{
Pin::new(&mut self.get_mut().0.as_mut().expect("async_task::Task is none")).poll(cx)
}
#[cfg(feature = "tokio")]
{
Pin::new(
&mut self
.get_mut()
.0
.as_mut()
.expect("tokio::task::JoinHandle is none"),
)
.poll(cx)
.map(|r| r.expect("tokio::task::JoinHandle error"))
}
}
}