baka 0.1.0

Stupid simple future executor!
Documentation
use futures::{
    future::{BoxFuture, FutureExt},
    task::{waker_ref, ArcWake},
};
use std::{
    cell::RefCell,
    future::Future,
    sync::mpsc::{sync_channel, Receiver, SyncSender},
    sync::{Arc, Mutex},
    task::Context,
};

struct Executor<T> {
    result: RefCell<Option<T>>,
    ready_queue: Receiver<Arc<Task<T>>>,
}

#[derive(Clone)]
struct Spawner<T> {
    task_sender: SyncSender<Arc<Task<T>>>,
}

struct Task<T> {
    future: Mutex<Option<BoxFuture<'static, T>>>,

    task_sender: SyncSender<Arc<Task<T>>>,
}

pub fn spawn<T>(future: impl Future<Output = T> + 'static + Send) -> T {
    const MAX_QUEUED_TASKS: usize = 1;
    let (task_sender, ready_queue) = sync_channel(MAX_QUEUED_TASKS);
    let (e, s) = (
        Executor {
            ready_queue,
            result: RefCell::new(None),
        },
        Spawner { task_sender },
    );
    s.spawn(future);
    e.run();
    e.result
        .take()
        .unwrap_or_else(|| panic!("executor had no result"))
}

impl<T> Spawner<T> {
    fn spawn(&self, future: impl Future<Output = T> + 'static + Send) {
        let future = future.boxed();
        let task = Arc::new(Task {
            future: Mutex::new(Some(future)),
            task_sender: self.task_sender.clone(),
        });
        self.task_sender.send(task).expect("too many tasks queued");
    }
}

impl<T> ArcWake for Task<T> {
    fn wake_by_ref(arc_self: &Arc<Self>) {
        let cloned = arc_self.clone();
        arc_self
            .task_sender
            .send(cloned)
            .expect("too many tasks queued");
    }
}

impl<T> Executor<T> {
    fn run(&self) {
        while let Ok(task) = self.ready_queue.recv() {
            let mut future_slot = task.future.lock().unwrap();
            if let Some(mut future) = future_slot.take() {
                let waker = waker_ref(&task);
                let context = &mut Context::from_waker(&waker);

                match future.as_mut().poll(context) {
                    std::task::Poll::Ready(val) => {
                        self.result.replace(Some(val));
                        break;
                    }
                    std::task::Poll::Pending => {
                        *future_slot = Some(future);
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let result = spawn(async { 1 + 2 });
        assert_eq!(result, 3);
    }

    #[test]
    fn it_returns_a_struct() {
        struct Foo {
            a: u32,
            b: u32,
        }

        let result = spawn(async { Foo { a: 1, b: 2 } });
        assert_eq!(result.a, 1);
        assert_eq!(result.b, 2);
    }
}