Documentation
use std::{future::Future, pin::Pin};

thread_local! {
    static SPAWNER: Box<dyn Spawner> = std::ptr::null();
}

pub struct Canceled;

pub trait Spawner {
    /// Runs the provided future, blocking the current thread until the future
    /// completes.
    fn block_on<F: Future<Output = ()>>(&self, fut: F);

    /// Spawn a future on the current thread. This does not create a new Arbiter
    /// or Arbiter address, it is simply a helper for spawning futures on the current
    /// thread.
    fn spawn<F: Future>(&self, f: F);

    /// Executes a future on the current thread. This does not create a new Arbiter
    /// or Arbiter address, it is simply a helper for executing futures on the current
    /// thread.
    fn spawn_fn<F, R>(&self, f: F)
    where
        F: FnOnce() -> R,
        R: Future,
    {
        self.spawn(async move { f().await })
    }

    /// Runs the provided closure on a thread where blocking is acceptable.
    fn spawn_blocking<F, R>(&self, f: F) -> Pin<Box<dyn Future<Output = Result<R, Canceled>>>>
    where
        F: FnOnce() -> R + Send + 'static,
        R: Send + 'static;
}