1#![no_std]
2extern crate alloc;
3use {
4 alloc::{boxed::Box, collections::vec_deque::VecDeque, sync::Arc},
5 core::{
6 future::Future,
7 pin::Pin,
8 task::{Context, Poll},
9 },
10 spin::Mutex,
11 woke::{waker_ref, Woke},
12};
13
14type TasksList = VecDeque<Box<dyn Pendable + core::marker::Send + core::marker::Sync>>;
15
16pub struct Executor {
17 tasks: Option<TasksList>,
18}
19
20trait Pendable {
21 fn is_pending(&self) -> bool;
22}
23
24struct Task<T> {
26 pub future: Mutex<Pin<Box<dyn Future<Output = T> + Send + 'static>>>,
27}
28
29impl<T> Woke for Task<T> {
31 fn wake_by_ref(_: &Arc<Self>) {
32 if let Some(mut e) = DEFAULT_EXECUTOR.try_lock() {
34 e.poll_tasks()
36 }
37 }
38}
39
40impl<T> Pendable for Arc<Task<T>> {
41 fn is_pending(&self) -> bool {
42 let mut future = self.future.lock();
43 let waker = waker_ref(self);
45 let context = &mut Context::from_waker(&*waker);
47 matches!(future.as_mut().poll(context), Poll::Pending)
48 }
49}
50
51impl Executor {
52 pub fn run<T>(&mut self, future: Pin<Box<dyn Future<Output = T> + 'static + Send>>)
54 where
55 T: Send + 'static,
56 {
57 self.add_task(future);
58 self.poll_tasks();
59 }
60
61 fn add_task<T>(&mut self, future: Pin<Box<dyn Future<Output = T> + 'static + Send>>)
63 where
64 T: Send + 'static,
65 {
66 let task = Arc::new(Task {
68 future: Mutex::new(future),
69 });
70 if self.tasks.is_none() {
71 self.tasks = Some(TasksList::new());
72 }
73 let tasks: &mut TasksList = self.tasks.as_mut().expect("tasks not initialized");
74 tasks.push_back(Box::new(task));
75 }
76
77 fn poll_tasks(&mut self) {
79 if self.tasks.is_none() {
80 self.tasks = Some(TasksList::new());
81 }
82 let tasks: &mut TasksList = self.tasks.as_mut().expect("tasks not initialized");
83 for _ in 0..tasks.len() {
84 let task = tasks.pop_front().unwrap();
85 if task.is_pending() {
86 tasks.push_back(task);
87 }
88 }
89 }
90}
91
92static DEFAULT_EXECUTOR: Mutex<Executor> = Mutex::new(Executor { tasks: None });
93
94pub fn run<T>(future: impl Future<Output = T> + 'static + Send)
95where
96 T: Send + 'static,
97{
98 DEFAULT_EXECUTOR.lock().run(Box::pin(future))
99}