use std::collections::LinkedList;
use std::future::Future;
use std::ops::Deref;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, LazyLock, Mutex};
use std::task::Poll;
use log::debug;
use crate::task::Task;
pub(crate) type Queue = Arc<Mutex<LinkedList<Arc<Task>>>>;
pub(crate) struct Runtime {
pub(crate) task_queue: Queue,
pub(crate) size: AtomicUsize,
}
impl Runtime {
fn start() {
std::thread::spawn(|| loop {
let task = match Runtime::get().pop_front() {
Some(task) => task,
None => continue,
};
if let Poll::Ready(_) = task.poll() {
debug!("Future returned");
}
});
}
pub fn get() -> &'static Runtime {
INSTANCE.deref()
}
fn pop_front(&self) -> Option<Arc<Task>> {
self.task_queue.lock().unwrap().pop_front()
}
pub fn spawn(&self, future: impl Future<Output = ()> + Send + 'static) {
self.inner_spawn(Task::new(false, future));
}
pub fn spawn_blocking(&self, future: impl Future<Output = ()> + Send + 'static) {
self.inner_spawn_blocking(Task::new(true, future));
}
pub(crate) fn inner_spawn(&self, task: Arc<Task>) {
self.task_queue.lock().unwrap().push_back(task);
}
pub(crate) fn inner_spawn_blocking(&self, task: Arc<Task>) {
self.task_queue.lock().unwrap().push_front(task);
}
}
pub(crate) static INSTANCE: LazyLock<Runtime> = LazyLock::new(|| configure());
fn configure() -> Runtime {
Runtime::start();
let queue = Arc::new(Mutex::new(LinkedList::new()));
Runtime {
task_queue: queue.to_owned(),
size: AtomicUsize::new(0),
}
}
pub fn spawn(future: impl Future<Output = ()> + Send + 'static) {
Runtime::get().spawn(future);
}
pub fn block_on(future: impl Future<Output = ()> + Send + 'static) {
Runtime::get().spawn_blocking(future);
}
pub fn wait() {
let runtime = Runtime::get();
while runtime.size.load(Ordering::Relaxed) > 0 {}
}