async-task 3.0.0

Task abstraction for building executors
Documentation
//! A simple single-threaded executor that can spawn non-`Send` futures.

use std::cell::Cell;
use std::future::Future;
use std::rc::Rc;

use crossbeam::channel::{unbounded, Receiver, Sender};

type Task = async_task::Task<()>;
type JoinHandle<T> = async_task::JoinHandle<T, ()>;

thread_local! {
    // A channel that holds scheduled tasks.
    static QUEUE: (Sender<Task>, Receiver<Task>) = unbounded();
}

/// Spawns a future on the executor.
fn spawn<F, R>(future: F) -> JoinHandle<R>
where
    F: Future<Output = R> + 'static,
    R: 'static,
{
    // Create a task that is scheduled by sending itself into the channel.
    let schedule = |t| QUEUE.with(|(s, _)| s.send(t).unwrap());
    let (task, handle) = async_task::spawn_local(future, schedule, ());

    // Schedule the task by sending it into the queue.
    task.schedule();

    handle
}

/// Runs a future to completion.
fn run<F, R>(future: F) -> R
where
    F: Future<Output = R> + 'static,
    R: 'static,
{
    // Spawn a task that sends its result through a channel.
    let (s, r) = unbounded();
    spawn(async move { s.send(future.await).unwrap() });

    loop {
        // If the original task has completed, return its result.
        if let Ok(val) = r.try_recv() {
            return val;
        }

        // Otherwise, take a task from the queue and run it.
        QUEUE.with(|(_, r)| r.recv().unwrap().run());
    }
}

fn main() {
    let val = Rc::new(Cell::new(0));

    // Run a future that increments a non-`Send` value.
    run({
        let val = val.clone();
        async move {
            // Spawn a future that increments the value.
            let handle = spawn({
                let val = val.clone();
                async move {
                    val.set(dbg!(val.get()) + 1);
                }
            });

            val.set(dbg!(val.get()) + 1);
            handle.await;
        }
    });

    // The value should be 2 at the end of the program.
    dbg!(val.get());
}