use crate::futures::FutureExt as _;
use crate::graceful::ShutdownGuard;
#[derive(Default, Debug, Clone)]
pub struct Executor {
guard: Option<ShutdownGuard>,
}
impl Executor {
#[must_use]
pub const fn new() -> Self {
Self { guard: None }
}
#[must_use]
pub fn graceful(guard: ShutdownGuard) -> Self {
Self { guard: Some(guard) }
}
pub fn spawn_task<F>(&self, future: F) -> tokio::task::JoinHandle<F::Output>
where
F: Future<Output: Send + 'static> + Send + 'static,
{
match &self.guard {
Some(guard) => {
let guard = guard.clone();
spawn(async move {
let output = future.await;
drop(guard);
output
})
}
None => spawn(future),
}
}
pub fn spawn_cancellable_task<F>(&self, future: F) -> tokio::task::JoinHandle<Option<F::Output>>
where
F: Future<Output: Send + 'static> + Send + 'static,
{
match &self.guard {
Some(guard) => {
let guard = guard.clone();
spawn(async move {
let output = tokio::select! {
_ = guard.cancelled() => {
tracing::trace!("cancellable task is cancelled due to guard");
None
}
output = future => {
Some(output)
}
};
drop(guard);
output
})
}
None => spawn(future.map(Some)),
}
}
pub fn into_spawn_task<F>(self, future: F) -> tokio::task::JoinHandle<F::Output>
where
F: Future<Output: Send + 'static> + Send + 'static,
{
match self.guard {
Some(guard) => spawn(async move {
let output = future.await;
drop(guard);
output
}),
None => spawn(future),
}
}
#[must_use]
pub fn guard(&self) -> Option<&ShutdownGuard> {
self.guard.as_ref()
}
#[must_use]
pub fn into_guard(self) -> Option<ShutdownGuard> {
self.guard
}
}
#[inline]
fn spawn<F>(future: F) -> tokio::task::JoinHandle<F::Output>
where
F: Future<Output: Send + 'static> + Send + 'static,
{
#[cfg(feature = "dial9")]
{
::dial9_tokio_telemetry::spawn(future)
}
#[cfg(not(feature = "dial9"))]
{
tokio::spawn(future)
}
}