slings 0.1.4

A small async runtime based on io-uring for Rust
Documentation
use std::future::Future;
use std::sync::Arc;

use async_task::{Runnable, Task};
use concurrent_queue::ConcurrentQueue;
use scoped_tls::scoped_thread_local;

const MAX_TASKS_PER_TICK: usize = 64;

pub struct LocalExecutor {
    queue: Arc<ConcurrentQueue<Runnable>>,
}

scoped_thread_local!(static EXECUTOR: LocalExecutor);

pub fn spawn_local<T: 'static>(future: impl Future<Output = T> + 'static) -> Task<T> {
    if !EXECUTOR.is_set() {
        panic!("`spawn` called from outside of a `LocalExecutor`");
    }

    EXECUTOR.with(|local_executor| local_executor.spawn_local(future))
}

impl LocalExecutor {
    pub fn new() -> LocalExecutor {
        LocalExecutor {
            queue: Arc::new(ConcurrentQueue::unbounded()),
        }
    }

    pub fn tick(&self) -> bool {
        for _ in 0..MAX_TASKS_PER_TICK {
            match self.next_task() {
                Some(task) => {
                    task.run();
                }
                None => return false,
            }
        }
        true
    }

    fn next_task(&self) -> Option<Runnable> {
        if let Ok(task) = self.queue.pop() {
            Some(task)
        } else {
            None
        }
    }

    pub fn spawn_local<T: 'static>(&self, future: impl Future<Output = T> + 'static) -> Task<T> {
        let queue = self.queue.clone();
        let schedule = move |runnable| {
            let _ = queue.push(runnable);
        };

        let (runnable, task) = async_task::spawn_local(future, schedule);
        runnable.schedule();
        task
    }

    pub(crate) fn with<T>(&self, f: impl FnOnce() -> T) -> T {
        EXECUTOR.set(&self, f)
    }
}