use super::RuntimeError;
use std::borrow::Cow;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use crate::{RuntimeGuard, RuntimeTicker};
pub type ProcFuture<'a> = Pin<Box<dyn Future<Output = Result<(), RuntimeError>> + Send + 'a>>;
pub trait Runnable
where
Self: Send + Sync + 'static,
{
fn process_start(&self) -> ProcFuture<'_>;
fn process_name(&self) -> Cow<'static, str> {
Cow::Borrowed(std::any::type_name::<Self>())
}
fn process_handle(&self) -> Arc<dyn ProcessControlHandler>;
}
pub struct RuntimeContext {
ticker: RuntimeTicker,
handle: Arc<dyn ProcessControlHandler>,
}
impl RuntimeContext {
fn new(ticker: RuntimeTicker, handle: Arc<dyn ProcessControlHandler>) -> Self {
Self { ticker, handle }
}
pub async fn tick<O, Fut>(&self, fut: Fut) -> ProcessOperation<O>
where
Fut: Future<Output = O>,
{
self.ticker.tick(fut).await
}
pub fn handle(&self) -> Arc<dyn ProcessControlHandler> {
Arc::clone(&self.handle)
}
}
pub trait RunnableWithContext
where
Self: Send + Sync + 'static,
{
fn process_start_with_context(&self, ctx: RuntimeContext) -> ProcFuture<'_>;
fn process_name(&self) -> Cow<'static, str> {
Cow::Borrowed(std::any::type_name::<Self>())
}
}
pub struct RuntimeContextRunnable<R>
where
R: RunnableWithContext,
{
inner: R,
runtime_guard: RuntimeGuard,
}
impl<R> RuntimeContextRunnable<R>
where
R: RunnableWithContext,
{
pub fn new(inner: R) -> Self {
Self {
inner,
runtime_guard: RuntimeGuard::default(),
}
}
}
pub fn with_runtime_context<R>(runnable: R) -> RuntimeContextRunnable<R>
where
R: RunnableWithContext,
{
RuntimeContextRunnable::new(runnable)
}
impl<R> Runnable for RuntimeContextRunnable<R>
where
R: RunnableWithContext,
{
fn process_start(&self) -> ProcFuture<'_> {
Box::pin(async move {
let ticker = self.runtime_guard.runtime_ticker().await;
let ctx = RuntimeContext::new(ticker, self.runtime_guard.handle());
self.inner.process_start_with_context(ctx).await
})
}
fn process_name(&self) -> Cow<'static, str> {
self.inner.process_name()
}
fn process_handle(&self) -> Arc<dyn ProcessControlHandler> {
self.runtime_guard.handle()
}
}
pub type CtrlFuture<'a> = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
pub trait ProcessControlHandler: Send + Sync {
fn shutdown(&self) -> CtrlFuture<'_>;
fn reload(&self) -> CtrlFuture<'_>;
}
pub enum ProcessOperation<T> {
Next(T),
Control(RuntimeControlMessage),
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum RuntimeControlMessage {
Reload,
Shutdown,
Custom(Arc<dyn std::any::Any + Send + Sync>),
}
impl<R> Runnable for Arc<R>
where
R: Runnable + ?Sized,
{
fn process_start(&self) -> ProcFuture<'_> {
R::process_start(self)
}
fn process_handle(&self) -> Arc<dyn ProcessControlHandler> {
R::process_handle(self)
}
fn process_name(&self) -> Cow<'static, str> {
R::process_name(self)
}
}