boomerang_runtime/action/
mod.rs

1use std::{
2    fmt::{Debug, Display},
3    sync::{Arc, Mutex},
4};
5
6use crate::{Duration, Tag};
7
8mod action_ref;
9mod store;
10
11pub use action_ref::*;
12use store::{ActionStore, BaseActionStore};
13
14#[cfg(not(feature = "serde"))]
15pub trait ActionData: std::fmt::Debug + Send + Sync + Clone + 'static {}
16
17#[cfg(not(feature = "serde"))]
18impl<T> ActionData for T where T: std::fmt::Debug + Send + Sync + Clone + 'static {}
19
20#[cfg(feature = "serde")]
21pub trait ActionData:
22    std::fmt::Debug
23    + Send
24    + Sync
25    + Clone
26    + serde::Serialize
27    + for<'de> serde::Deserialize<'de>
28    + 'static
29{
30}
31
32#[cfg(feature = "serde")]
33impl<T> ActionData for T where
34    T: std::fmt::Debug
35        + Send
36        + Sync
37        + Clone
38        + serde::Serialize
39        + for<'de> serde::Deserialize<'de>
40        + 'static
41{
42}
43
44tinymap::key_type! {
45    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
46    pub ActionKey
47}
48
49/// Typed Action state, storing potentially different values at different Tags.
50#[derive(Debug)]
51pub struct LogicalAction {
52    pub name: String,
53    pub key: ActionKey,
54    pub min_delay: Duration,
55    pub store: Box<dyn BaseActionStore>,
56}
57
58impl LogicalAction {
59    pub fn new<T: ActionData>(name: &str, key: ActionKey, min_delay: Duration) -> Self {
60        let store = ActionStore::<T>::new();
61        Self {
62            name: name.into(),
63            key,
64            min_delay,
65            store: Box::new(store),
66        }
67    }
68}
69
70#[derive(Debug)]
71pub struct PhysicalAction {
72    pub name: String,
73    pub key: ActionKey,
74    pub min_delay: Duration,
75    pub store: Arc<Mutex<dyn BaseActionStore>>,
76}
77
78impl PhysicalAction {
79    pub fn new<T: ActionData>(name: &str, key: ActionKey, min_delay: Duration) -> Self {
80        let store = ActionStore::<T>::new();
81        let store: Arc<Mutex<dyn BaseActionStore>> = Arc::new(Mutex::new(store));
82        Self {
83            name: name.into(),
84            key,
85            min_delay,
86            store,
87        }
88    }
89
90    /// Create a new Arrow ArrayBuilder for the data stored in this store
91    #[cfg(feature = "serde")]
92    pub fn new_builder(&self) -> Result<serde_arrow::ArrayBuilder, crate::RuntimeError> {
93        self.store.lock().expect("lock").new_builder()
94    }
95
96    /// Serialize the latest value in the store to the given `ArrayBuilder`.
97    #[cfg(feature = "serde")]
98    pub fn build_value_at(
99        &mut self,
100        builder: &mut serde_arrow::ArrayBuilder,
101        tag: Tag,
102    ) -> Result<(), crate::RuntimeError> {
103        self.store
104            .lock()
105            .expect("lock")
106            .build_value_at(builder, tag)
107    }
108}
109
110#[derive(Debug)]
111pub enum Action {
112    /// Startup is a special action that fires when the scheduler starts up.
113    Startup,
114    /// Shutdown is a special action that fires when the scheduler shuts down.
115    Shutdown,
116    Logical(LogicalAction),
117    Physical(PhysicalAction),
118}
119
120impl Action {
121    pub fn as_valued(&self) -> Option<&LogicalAction> {
122        if let Self::Logical(v) = self {
123            Some(v)
124        } else {
125            None
126        }
127    }
128
129    pub fn as_valued_mut(&mut self) -> Option<&mut LogicalAction> {
130        if let Self::Logical(v) = self {
131            Some(v)
132        } else {
133            None
134        }
135    }
136
137    pub fn as_physical(&mut self) -> Option<&mut PhysicalAction> {
138        if let Self::Physical(v) = self {
139            Some(v)
140        } else {
141            None
142        }
143    }
144}
145
146impl Display for Action {
147    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148        match self {
149            Action::Startup => f.write_fmt(format_args!("Action::Startup")),
150            Action::Shutdown => f.write_fmt(format_args!("Action::Shutdown")),
151            Action::Logical(LogicalAction { name, .. }) => {
152                f.write_fmt(format_args!("Action::Logical<{name}>"))
153            }
154            Action::Physical(PhysicalAction { name, .. }) => {
155                f.write_fmt(format_args!("Action::Physical<{name}>"))
156            }
157        }
158    }
159}
160
161impl AsRef<Action> for Action {
162    fn as_ref(&self) -> &Self {
163        self
164    }
165}
166
167impl AsMut<Action> for Action {
168    fn as_mut(&mut self) -> &mut Action {
169        self
170    }
171}