yaaral 0.5.3

yet another async runtime abstraction library
Documentation
#![doc = include_str!("../README.MD")]
#![warn(missing_docs)]

use std::fmt::Debug;

use std::future::Future;

mod extensions;
pub mod prelude;
mod utils;

#[cfg(any(feature = "bevy_runtime", feature = "bevy_runtime_018"))]
pub mod bevy;

#[cfg(feature = "futures_runtime")]
pub mod futures;

#[cfg(feature = "tokio_runtime")]
pub mod tokio;

pub use utils::Infallible;

#[cfg(feature = "compat")]
pub use extensions::compat;

#[cfg(feature = "http")]
pub use extensions::http;

#[cfg(feature = "time")]
pub use extensions::time;

/// Interface for a task
pub trait TaskHandle {
    /// The type returned by the future
    type Output;
    /// The error that can be returned when joining
    type JoinError: Debug;
    /// Join the task, wait for completion, and return its output
    fn join(self) -> impl Future<Output = Result<Self::Output, Self::JoinError>>;
    /// Abort the task
    fn abort(self);
    /// Cancel the task, and wait for the cancellation to finish
    fn cancel(self) -> impl Future<Output = ()> + Send;
    /// Detach, so that the task keep executing in the background
    fn detach(self);
}

/// Allow to detach a `Result<TaskHandle>`
pub trait TaskReturnHandle {
    /// The error type
    type Error;
    /// Detach, so that the task keep executing in the background
    fn detach(self) -> Result<(), Self::Error>;
}

impl<TH, E> TaskReturnHandle for Result<TH, E>
where
    TH: TaskHandle,
{
    type Error = E;
    fn detach(self) -> Result<(), Self::Error> {
        self.map(|x| x.detach())
    }
}

/// Interface for managing task for runtimes
pub trait TaskInterface: Send + Sync + Clone + 'static {
    /// Result of spawning a task
    type TaskHandle<T: 'static + Send>: TaskHandle<Output = T, JoinError = Self::JoinError>;

    /// Error type for errors occuring during spawning
    type SpawnError: Debug;

    /// Error type when creating
    type JoinError: Debug;

    /// Spawn a task
    fn spawn_task<F, T>(
        &self,
        future: F,
    ) -> Result<utils::TaskHandle<Self::TaskHandle<F::Output>>, Self::SpawnError>
    where
        F: Future<Output = T> + Send + 'static,
        T: Send + 'static;

    /// Block on task
    fn block_on<F: Future>(&self, future: F) -> F::Output;
}

/// Configuration of a runtime
pub struct Config {
    pub(crate) thread_count: Option<usize>,
    pub(crate) prefix: Option<String>,
}

impl Config {
    /// New default config, with default number of threads.
    pub fn new() -> Self {
        Self {
            thread_count: None,
            prefix: None,
        }
    }
    /// Prefix of the runtime threads
    pub fn prefix(mut self, prefix: impl Into<String>) -> Self {
        self.prefix = Some(prefix.into());
        self
    }
    /// Set the number of threads
    pub fn thread_count(mut self, thread_count: usize) -> Self {
        self.thread_count = Some(thread_count);
        self
    }
}

impl Default for Config {
    fn default() -> Self {
        Self::new()
    }
}

/// Full interface for Runtime, including creation
pub trait CreationInterface: TaskInterface {
    /// Error type when creating
    type NewError: Debug;

    /// Create a new runtime
    fn new(config: Config) -> Result<Self, Self::NewError>;
}

#[cfg(test)]
#[path = "../tests/common/mod.rs"]
mod common;

#[cfg(all(test, any(feature = "futures_runtime", feature = "tokio_runtime")))]
mod test {
    use super::common;

    use crate::{Config, CreationInterface};

    fn test_full_runtime<RT: CreationInterface>() {
        let rt = RT::new(Config::new().prefix("test")).unwrap();
        common::test_runtime_tasks(&rt);
    }
    #[cfg(feature = "futures_runtime")]
    #[test]
    fn test_futures() {
        test_full_runtime::<crate::futures::Runtime>();
    }
    #[cfg(feature = "tokio_runtime")]
    #[test]
    fn test_tokio() {
        test_full_runtime::<crate::tokio::Runtime>();
    }
}