Files
orchid/orchid-extension/src/tokio.rs
Lawrence Bethlenfalvy 0909524dee
Some checks failed
Rust / build (push) Failing after 3m52s
Compiles again after command subsystem
terrified to start testing
2026-03-27 23:50:58 +01:00

66 lines
1.9 KiB
Rust

use std::rc::Rc;
use crate::{ExtPort, ExtensionBuilder};
/// Run an extension inside a Tokio localset. Since the extension API does not
/// provide a forking mechanism, it can safely abort once the localset is
/// exhausted. If an extension absolutely needs a parallel thread, it can import
/// and call [tokio::task::spawn_local] which will keep alive the localset and
/// postpone the aggressive shutdown, and listen for the [Drop::drop] of the
/// value returned by [crate::system_ctor::SystemCtor::inst] to initiate
/// shutdown.
#[cfg(feature = "tokio")]
pub async fn __tokio_entrypoint(builder: ExtensionBuilder) {
use std::cell::RefCell;
use async_event::Event;
use tokio::io::{stderr, stdin, stdout};
use tokio::task::{LocalSet, spawn_local};
use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
let cc = Rc::new(Event::new());
let c = Rc::new(RefCell::new(1));
LocalSet::new()
.run_until(async {
let counter = (c.clone(), cc.clone());
builder
.run(ExtPort {
input: Box::pin(stdin().compat()),
output: Box::pin(stdout().compat_write()),
log: Box::pin(stderr().compat_write()),
spawn: Rc::new(move |delay, fut| {
let (c, cc) = counter.clone();
if delay.is_zero() {
*c.borrow_mut() += 1;
cc.notify_all();
spawn_local(async move {
fut.await;
*c.borrow_mut() -= 1;
cc.notify_all();
});
} else {
let at = tokio::time::Instant::now() + delay;
spawn_local(async move {
tokio::time::sleep_until(at).await;
*c.borrow_mut() += 1;
cc.notify_all();
fut.await;
*c.borrow_mut() -= 1;
cc.notify_all();
});
}
}),
})
.await;
cc.wait_until(|| (*c.borrow() == 0).then_some(())).await;
})
.await;
}
#[macro_export]
macro_rules! tokio_main {
($builder:expr) => {
#[tokio::main]
pub async fn main() { $crate::__tokio_entrypoint($builder).await }
};
}