actm 0.1.0

Tiny async actors framework for rust
Documentation
//! Abstraction over various executors that actors can run on
use std::{convert::Infallible, future::Future};

use async_trait::async_trait;
use futures::future::BoxFuture;

#[cfg(feature = "async-std")]
pub mod asyncstd;
pub mod threads;

#[cfg(feature = "async-std")]
pub use asyncstd::AsyncStd;
pub use threads::Threads;

use crate::types::Either;

/// Asynchronous join handle
///
/// Provides an executor-agnostic abstraction over joining an asynchronous task
#[async_trait]
pub trait AsyncJoin {
    /// Item being joined
    type Item;
    /// Error type for failed joins
    type Error: std::error::Error + 'static;
    /// Asynchronously join this task
    ///
    /// # Errors
    ///
    /// Returns an error if joining the task fails
    async fn async_join(self) -> Result<Self::Item, Self::Error>;
}

#[async_trait]
impl<T> AsyncJoin for BoxFuture<'static, T>
where
    T: Send,
{
    type Item = T;
    type Error = Infallible;
    async fn async_join(self) -> Result<Self::Item, Self::Error> {
        Ok(self.await)
    }
}

/// Synchronous join handle
///
/// Provides an executor-agnostic abstraction over joining synchronous/blocking tasks or threads
pub trait SyncJoin {
    /// Item being joined
    type Item;
    /// Error type for failed joins
    type Error: std::error::Error + 'static;
    /// Synchronously join this thread
    ///
    /// # Errors
    ///
    /// Returns an error if joining the task fails
    fn sync_join(self) -> Result<Self::Item, Self::Error>;
    /// Attempts to convert this handle to an asynchronous one
    ///
    /// Will return `Either::Happy` if the conversion is possible, `Either::Sad` otherwise
    fn to_async(self) -> Either<Box<dyn AsyncJoin<Item = Self::Item, Error = Self::Error>>, Self>
    where
        Self: Sized,
    {
        Either::Sad(self)
    }
}

/// Abstract executor for actors
pub trait Executor: Send + Sync + 'static {
    /// Async join handle
    type AsyncJoin<T: Send + 'static>: AsyncJoin<Item = T>;
    /// Sync join handle
    type SyncJoin<T: Send + 'static>: SyncJoin<Item = T>;
    /// Spawns a future onto the executor as a task, returning a handle that can be `.await`ed for
    /// its result
    ///
    /// On async executors, this corresponds to an asynchronous task.
    /// On the [`Threads`] executor, this corresponds to a new thread with a single-threaded futures
    /// executor running on it.
    fn spawn_async<T, F>(future: F) -> Self::AsyncJoin<T>
    where
        T: Send + Sync + 'static,
        F: Future<Output = T> + Send + 'static;
    /// Spawns a closure onto its own system thread or blocking task, returning a handle that can be
    /// blocked on for its result
    ///
    /// On async executors this corresponds to a task on the blocking thread pool, or a new thread
    /// if the executor does not provide a blocking thread pool
    /// On the [`Threads`] executor, this corresponds to a new thread.
    fn spawn_sync<T, C>(closure: C) -> Self::SyncJoin<T>
    where
        T: Send + Sync + 'static,
        C: FnOnce() -> T + Send + 'static;
}