use crate::Routine;
use async_trait::async_trait;
use crb_core::time::Duration;
use crb_runtime::{Context, Controller, Failures, Interruptor, ManagedContext, Runtime};
struct RoutineRuntime<T: Routine> {
routine: T,
context: T::Context,
failures: Failures,
}
impl<T> RoutineRuntime<T>
where
T: Routine,
{
pub fn new(routine: T) -> Self
where
T::Context: Default,
{
Self {
routine,
context: T::Context::default(),
failures: Failures::default(),
}
}
}
#[async_trait]
impl<T> Runtime for RoutineRuntime<T>
where
T: Routine,
{
type Context = T::Context;
fn get_interruptor(&mut self) -> Box<dyn Interruptor> {
self.context.session().controller.interruptor()
}
async fn routine(mut self) -> Failures {
let mut ctx = self.context;
let result = self.routine.routine(&mut ctx).await;
let result = self.routine.finalize(result).await;
self.failures.put(result);
self.failures
}
fn context(&self) -> &Self::Context {
&self.context
}
}
pub struct RoutineSession {
controller: Controller,
interval: Duration,
}
impl RoutineSession {
pub fn set_interval(&mut self, interval: Duration) {
self.interval = interval;
}
pub fn interval(&self) -> Duration {
self.interval
}
}
impl Context for RoutineSession {
type Address = ();
fn address(&self) -> &Self::Address {
&()
}
}
impl ManagedContext for RoutineSession {
fn controller(&mut self) -> &mut Controller {
&mut self.controller
}
fn shutdown(&mut self) {
self.controller.stop(false).ok();
}
}
pub trait RoutineContext: Context {
fn session(&mut self) -> &mut RoutineSession;
}
impl RoutineContext for RoutineSession {
fn session(&mut self) -> &mut RoutineSession {
self
}
}
pub trait Standalone: Routine {
fn spawn(self)
where
Self::Context: Default;
}
impl<T: Routine + 'static> Standalone for T {
fn spawn(self)
where
Self::Context: Default,
{
let mut runtime = RoutineRuntime::new(self);
let address = runtime.context.session().address().clone();
crb_core::spawn(runtime.entrypoint());
address
}
}