hyperclock/components/
task.rs

1//! Defines complex, multi-step, stateful tasks, such as lifecycle loops.
2
3use crate::common::{ListenerId, TaskId};
4use crate::events::AutomationEvent;
5use tokio::sync::broadcast;
6
7/// A function closure that represents one step in a lifecycle.
8pub type LifecycleStep = Box<dyn FnMut() + Send + Sync>;
9
10/// Defines the repetition behavior of a `LifecycleLoop`.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum RepetitionPolicy {
13    /// The lifecycle runs through its steps once and then completes.
14    RunOnce,
15    /// The lifecycle runs through its steps N times and then completes.
16    RunNTimes(u32),
17    /// The lifecycle repeats indefinitely.
18    Repeat,
19}
20
21/// A stateful automation that executes a sequence of tasks in order.
22#[doc(hidden)]
23pub(crate) struct LifecycleLoop {
24    pub id: TaskId,
25    pub listener_id: ListenerId,
26    steps: Vec<LifecycleStep>,
27    current_step: usize,
28    repetition_policy: RepetitionPolicy,
29    run_count: u32,
30}
31
32impl LifecycleLoop {
33    /// Creates a new `LifecycleLoop`.
34    pub(crate) fn new(
35        id: TaskId,
36        listener_id: ListenerId,
37        steps: Vec<LifecycleStep>,
38        repetition_policy: RepetitionPolicy,
39    ) -> Self {
40        Self {
41            id,
42            listener_id,
43            steps,
44            current_step: 0,
45            repetition_policy,
46            run_count: 0,
47        }
48    }
49
50    /// Processes a `TaskFired` event to advance the lifecycle's state.
51    /// Returns `true` if the lifecycle has completed and should be removed.
52    pub(crate) fn advance(
53        &mut self,
54        automation_event_sender: &broadcast::Sender<AutomationEvent>,
55    ) -> bool {
56        if self.steps.is_empty() {
57            return true;
58        }
59        if let Some(step) = self.steps.get_mut(self.current_step) {
60            (step)();
61        }
62
63        automation_event_sender
64            .send(AutomationEvent::LifecycleStepAdvanced {
65                id: self.id,
66                step_index: self.current_step,
67            })
68            .ok();
69
70        self.current_step += 1;
71
72        if self.current_step >= self.steps.len() {
73            self.run_count += 1;
74            self.current_step = 0;
75
76            match self.repetition_policy {
77                RepetitionPolicy::RunOnce => {
78                    automation_event_sender
79                        .send(AutomationEvent::LifecycleCompleted { id: self.id })
80                        .ok();
81                    return true;
82                }
83                RepetitionPolicy::RunNTimes(n) => {
84                    if self.run_count >= n {
85                        automation_event_sender
86                            .send(AutomationEvent::LifecycleCompleted { id: self.id })
87                            .ok();
88                        return true;
89                    } else {
90                        automation_event_sender
91                            .send(AutomationEvent::LifecycleLooped { id: self.id })
92                            .ok();
93                    }
94                }
95                RepetitionPolicy::Repeat => {
96                    automation_event_sender
97                        .send(AutomationEvent::LifecycleLooped { id: self.id })
98                        .ok();
99                }
100            }
101        }
102        false
103    }
104}