makepad/libs/futures/src/executor.rs
2026-02-10 18:26:51 +01:00

113 lines
2.4 KiB
Rust

use std::{
error, fmt,
future::Future,
pin::Pin,
sync::{
mpsc::{Receiver, Sender},
Arc, Mutex,
},
task::Wake,
};
#[derive(Debug)]
pub struct Executor {
task_receiver: Receiver<Arc<Task>>,
}
impl Executor {
pub fn run(&self) {
while let Ok(task) = self.task_receiver.recv() {
task.run();
}
}
pub fn run_until_stalled(&self) {
while let Ok(task) = self.task_receiver.try_recv() {
task.run();
}
}
}
#[derive(Clone, Debug)]
pub struct Spawner {
task_sender: Sender<Arc<Task>>,
}
impl Spawner {
pub fn spawn(&self, future: impl Future<Output = ()> + 'static) -> Result<(), SpawnError> {
if self
.task_sender
.send(Arc::new(Task {
inner: Mutex::new(TaskInner {
future: Some(Box::pin(future)),
task_sender: self.task_sender.clone(),
}),
}))
.is_err()
{
return Err(SpawnError::shutdown());
}
Ok(())
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct SpawnError {
_priv: (),
}
impl SpawnError {
pub fn shutdown() -> Self {
Self { _priv: () }
}
}
impl error::Error for SpawnError {}
impl fmt::Display for SpawnError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "executor is shutdown")
}
}
struct Task {
inner: Mutex<TaskInner>,
}
impl Task {
fn run(self: Arc<Task>) {
use {crate::task, std::task::Context};
let future = self.inner.lock().unwrap().future.take();
if let Some(mut future) = future {
let waker = task::waker(self.clone());
let mut cx = Context::from_waker(&waker);
if future.as_mut().poll(&mut cx).is_pending() {
self.inner.lock().unwrap().future = Some(future);
}
}
}
}
impl Wake for Task {
fn wake(self: Arc<Task>) {
self.inner
.lock()
.unwrap()
.task_sender
.send(self.clone())
.unwrap();
}
}
struct TaskInner {
future: Option<Pin<Box<dyn Future<Output = ()> + 'static>>>,
task_sender: Sender<Arc<Task>>,
}
pub fn new_executor_and_spawner() -> (Executor, Spawner) {
use std::sync::mpsc;
let (task_sender, task_receiver) = mpsc::channel();
(Executor { task_receiver }, Spawner { task_sender })
}