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 core::iter::FromFn;
use std::pin::Pin;
use std::task::{Context, Poll};
use async_trait::async_trait;
use embassy_executor::raw::TaskStorage;
use embassy_executor::SpawnToken;
use futures_task::SpawnError;

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


#[cfg(feature = "exec_embassy")]
pub struct EmbassyExecutor {
    spawner: Option<embassy_executor::SendSpawner>,
    ticker: Option<embassy_time::Ticker>
}

#[cfg(feature = "exec_embassy")]
#[async_trait]
impl Executor<embassy_executor::SendSpawner> for EmbassyExecutor {
    async fn context() -> Result<Self, SpawnError> {
        let spawner = embassy_executor::SendSpawner::for_current_executor().await;
        Ok(Self {
            spawner: Some(spawner),
            ticker: None
        })
    }

    async fn set_context(&mut self, executor: embassy_executor::SendSpawner) {
        self.spawner = Some(executor);
    }

    async fn enter_context(&self) {
        match EmbassyExecutor::context().await {
            Ok(_) => {},
            Err(_) => {}
        }
    }

    async fn get_executor(&self) -> &embassy_executor::SendSpawner {
        match &self.spawner {
            Some(spawner) => spawner,
            None => panic!("No executor available")
        }
    }

    fn context_sync() -> Result<Self, SpawnError> {
        panic!("Sync not supported")
    }

    fn set_context_sync(&mut self, executor: embassy_executor::SendSpawner) {
        panic!("Sync not supported")
    }

    fn enter_context_sync(&self) {
        panic!("Sync not supported")
    }

    fn get_executor_sync(&self) -> &embassy_executor::SendSpawner {
        panic!("Sync not supported")
    }
}




#[cfg(feature = "exec_embassy")]
#[async_trait]
impl ExecutorPerform<embassy_executor::SendSpawner> for EmbassyExecutor {
    async fn spawn_in_context<F>(future: F) -> Result<Arc<dyn crate::Task<F::Output, Output = F::Output>>, futures_task::SpawnError>
        where
            F: Future + Send + 'static,
            F::Output: Send + 'static
    {
        let func = {
            async move { future.await }
        };

        let spawner = embassy_executor::SendSpawner::for_current_executor().await;
        match spawner.spawn(func) {
            Ok(_) => Ok(Arc::new(Task::new())),
            Err(e) => Err(SpawnError::shutdown())
        }
    }

    async fn spawn_from_executor<E, F>(executor: &E, future: F) -> Result<Arc<dyn crate::Task<F::Output, Output = F::Output>>, futures_task::SpawnError>
        where
            E: Executor<embassy_executor::SendSpawner>,
            F: Future + Send + 'static,
            F::Output: Send + 'static
    {
        let spawner = executor.get_executor().await;
        match spawner.spawn(future) {
            Ok(_) => Ok(Arc::new(Task::new())),
            Err(e) => Err(SpawnError::shutdown())
        }
    }

    async fn block_from_executor<E, F>(executor: &E, future: F) -> F::Output
        where
            E: Executor<embassy_executor::SendSpawner>,
            F: Future + Send + 'static,
            F::Output: Send + 'static
    {
        panic!("Block is not supported")
    }

    fn spawn_in_context_sync<F>(future: F) -> Result<Arc<dyn crate::Task<F::Output, Output = F::Output>>, futures_task::SpawnError>
        where
            F: Future + Send + 'static,
            F::Output: Send + 'static {
        panic!("Sync not supported")
    }

    fn spawn_from_executor_sync<E, F>(executor: &E, future: F) -> Result<Arc<dyn crate::Task<F::Output, Output = F::Output>>, futures_task::SpawnError>
        where
            E: Executor<embassy_executor::SendSpawner>,
            F: Future + Send + 'static,
            F::Output: Send + 'static {
        panic!("Sync not supported")
    }

    fn block_from_executor_sync<E, F>(executor: &E, future: F) -> F::Output
        where
            E: Executor<embassy_executor::SendSpawner>,
            F: Future + Send + 'static,
            F::Output: Send + 'static {
        panic!("Sync not supported")
    }
}




#[cfg(feature = "exec_embassy")]
#[async_trait]
impl Timer for EmbassyExecutor {
    async fn once(duration_millis: u32) -> Self {
        EmbassyExecutor::interval(duration_millis).await
    }

    async fn interval(duration_millis: u32) -> Self {
        let duration = embassy_time::Duration::from_millis(u64::from(duration_millis));
        let interval = embassy_time::Ticker::every(duration);

        Self {
            spawner: None,
            ticker: Some(interval)
        }
    }

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

    fn once_sync(duration_millis: u32) -> Self {
        EmbassyExecutor::interval_sync(duration_millis)
    }

    fn interval_sync(duration_millis: u32) -> Self {
        let duration = embassy_time::Duration::from_millis(u64::from(duration_millis));
        let interval = embassy_time::Ticker::every(duration);

        Self {
            spawner: None,
            ticker: Some(interval)
        }
    }

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

    async fn tick(&mut self) -> u32 {
        match &mut self.ticker {
            None => panic!("Timer has been dropped"),
            Some(ticker) => ticker.next().await
        };

        0
    }
}

#[cfg(feature = "exec_embassy")]
impl Clone for EmbassyExecutor {
    fn clone(&self) -> Self {
        Self {
            spawner: self.spawner.clone(),
            ticker: None
        }
    }
}




#[cfg(feature = "exec_embassy")]
pub struct Task<T> {
    token: Option<SpawnToken<T>>
}

#[cfg(feature = "exec_embassy")]
impl<T> Task<T> {
    pub fn new() -> Self {
        Self {
            token: None
        }
    }
}

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

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

impl<T: Send + 'static> crate::Task<T> for Task<T> {
    async fn output(self) -> T {}

    fn detach(mut self) {}

    fn drop(self) {}
}



#[cfg(all(feature = "hyper_executor", feature = "exec_embassy"))]
impl<F> hyper::rt::Executor<F> for EmbassyExecutor
    where
        F: core::future::Future + Send + 'static,
        F::Output: Send + 'static
{
    fn execute(&self, fut: F) {
        match EmbassyExecutor::spawn_in_context_sync(fut) {
            Ok(_) => {}
            Err(_) => {}
        }
    }
}