product-os-async-executor 0.0.18

Product OS : Async Executor provides a set of tools to handle async execution generically so that the desired async library (e.g. tokio, smol) to be used can be chosen at compile time.
Documentation
use std::prelude::v1::*;

use alloc::sync::Arc;
use std::pin::Pin;
use std::task::{Context, Poll};
use async_trait::async_trait;
use futures_task::SpawnError;
use futures_util::StreamExt;
use smol::future;

use crate::{Future, Timer};
use crate::{Executor, ExecutorPerform};


#[cfg(feature = "exec_smol")]
/// Smol-based executor implementation.
///
/// This executor wraps a Smol executor and provides timer functionality.
pub struct SmolExecutor<'a> {
    executor: Option<smol::Executor<'a>>,
    timer: Option<smol::Timer>
}


#[cfg(feature = "exec_smol")]
#[async_trait]
impl<'a> Executor<smol::Executor<'a>> for SmolExecutor<'a> {
    async fn context() -> Result<Self, SpawnError> {
        let executor = smol::Executor::new();
        Ok(Self {
            executor: Some(executor),
            timer: None
        })
    }

    async fn set_context(&mut self, executor: smol::Executor<'a>) {
        self.executor = Some(executor);
    }

    async fn enter_context(&self) {
        todo!()
    }

    async fn get_executor(&self) -> &smol::Executor<'a> {
        self.executor.as_ref().expect("No executor available")
    }

    fn context_sync() -> Result<Self, SpawnError> {
        let executor = smol::Executor::new();
        Ok(Self {
            executor: Some(executor),
            timer: None
        })
    }

    fn set_context_sync(&mut self, executor: smol::Executor<'a>) {
        self.executor = Some(executor);
    }

    fn enter_context_sync(&self) {
        todo!()
    }

    fn get_executor_sync(&self) -> &smol::Executor<'a> {
        self.executor.as_ref().expect("No executor available")
    }
}



#[cfg(feature = "exec_smol")]
#[async_trait]
impl<'a> ExecutorPerform<smol::Executor<'a>> for SmolExecutor<'a> {
    async fn spawn_in_context<F>(future: F) -> Result<Arc<dyn crate::Task<F::Output, Output = F::Output>>, SpawnError>
        where
            F: Future + Send + 'static,
            F::Output: Send + 'static
    {
        let handle = smol::spawn(future);
        Ok(Arc::new(Task::new(handle)))
    }

    async fn spawn_from_executor<E, F>(executor: &E, future: F) -> Result<Arc<dyn crate::Task<F::Output, Output = F::Output>>, SpawnError>
        where
            E: Executor<smol::Executor<'a>>,
            F: Future + Send + 'static,
            F::Output: Send + 'static {
        let exec = executor.get_executor().await;
        Ok(Arc::new(Task::new(exec.spawn(future))))
    }

    async fn block_from_executor<E, F>(executor: &E, future: F) -> F::Output
        where
            E: Executor<smol::Executor<'a>>,
            F: Future + Send + 'static,
            F::Output: Send + 'static {
        let exec = executor.get_executor().await;
        future::block_on(exec.run(future))
    }

    fn spawn_in_context_sync<F>(future: F) -> Result<Arc<dyn crate::Task<F::Output, Output = F::Output>>, SpawnError>
        where
            F: Future + Send + 'static,
            F::Output: Send + 'static
    {
        let handle = smol::spawn(future);
        Ok(Arc::new(Task::new(handle)))
    }

    fn spawn_from_executor_sync<E, F>(executor: &E, future: F) -> Result<Arc<dyn crate::Task<F::Output, Output = F::Output>>, SpawnError>
        where
            E: Executor<smol::Executor<'a>>,
            F: Future + Send + 'static,
            F::Output: Send + 'static {
        let exec = executor.get_executor_sync();
        Ok(Arc::new(Task::new(exec.spawn(future))))
    }

    fn block_from_executor_sync<E, F>(executor: &E, future: F) -> F::Output
        where
            E: Executor<smol::Executor<'a>>,
            F: Future + Send + 'static,
            F::Output: Send + 'static {
        let exec = executor.get_executor_sync();
        future::block_on(exec.run(future))
    }
}



#[cfg(feature = "exec_smol")]
#[async_trait]
impl Timer for SmolExecutor<'_> {
    async fn once(duration_millis: u32) -> Self {
        let duration = std::time::Duration::from_millis(u64::from(duration_millis));
        let once = smol::Timer::after(duration);

        Self {
            executor: None,
            timer: Some(once)
        }
    }

    async fn interval(duration_millis: u32) -> Self {
        let duration = std::time::Duration::from_millis(u64::from(duration_millis));
        let interval = smol::Timer::interval(duration);

        Self {
            executor: None,
            timer: Some(interval)
        }
    }

    async fn cancel(&mut self) {
        self.timer = None;
    }

    fn once_sync(duration_millis: u32) -> Self {
        let duration = std::time::Duration::from_millis(u64::from(duration_millis));
        let once = smol::Timer::after(duration);

        Self {
            executor: None,
            timer: Some(once)
        }
    }

    fn interval_sync(duration_millis: u32) -> Self {
        let duration = std::time::Duration::from_millis(u64::from(duration_millis));
        let interval = smol::Timer::interval(duration);

        Self {
            executor: None,
            timer: Some(interval)
        }
    }

    fn cancel_sync(&mut self) {
        self.timer = None;
    }

    async fn tick(&mut self) -> u32 {
        let timer = self.timer.as_mut().expect("Timer has been dropped");
        timer.next().await.map_or(0, |i| u32::try_from(i.elapsed().as_millis()).unwrap_or(0))
    }
}

#[cfg(feature = "exec_smol")]
impl Clone for SmolExecutor<'_> {
    fn clone(&self) -> Self {
        Self {
            executor: None,
            timer: None,
        }
    }
}


#[cfg(feature = "exec_smol")]
pub struct Task<T> {
    handle: smol::Task<T>
}

#[cfg(feature = "exec_smol")]
impl<T> Task<T> {
    pub const fn new(handle: smol::Task<T>) -> Self {
        Self {
            handle
        }
    }
}

#[cfg(feature = "exec_smol")]
impl<T> Future for Task<T> {
    type Output = T;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let handle = &mut self.get_mut().handle;

        Poll::Ready(futures_util::ready!(Pin::new(handle).poll(cx)))
    }
}

#[cfg(feature = "exec_smol")]
#[async_trait]
impl<T: Send + 'static> crate::Task<T> for Task<T> {
    async fn output(self) -> T {
        self.handle.await
    }

    fn detach(self) {
        self.handle.detach();
    }

    fn drop(self) {
        drop(self);
    }
}


#[cfg(all(feature = "hyper_executor", feature = "exec_smol"))]
impl<F> hyper::rt::Executor<F> for SmolExecutor<'_>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static
{
    fn execute(&self, fut: F) {
        let _ = SmolExecutor::spawn_in_context_sync(fut);
    }
}