crb_routine/
runtime.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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 between repeatable routine calls
    interval: Duration,
}

impl RoutineSession {
    /// Set repeat interval.
    pub fn set_interval(&mut self, interval: Duration) {
        self.interval = interval;
    }

    pub fn interval(&self) -> Duration {
        self.interval
    }
}

impl Context for RoutineSession {
    // TODO: TaskAddress that uses a controller internally
    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
    }
}