1#![deny(missing_docs)]
2
3use uuid::Uuid;
14use std::sync::Arc;
15use thiserror::Error;
16use async_trait::async_trait;
17
18pub mod prelude;
25
26mod context;
27mod runtime;
28
29pub use runtime::{Runtime, RuntimeBuilder};
30
31#[async_trait]
39pub trait Action: Send + Sync {
40 async fn run(&self, runtime: Runtime, operation: Operation) -> Result<Option<ActionOutput>, ActionError>;
47
48 async fn probe(&self, runtime: Runtime) -> Result<Probe, ActionError>;
50
51 async fn load_state(&self, _builder: &mut RuntimeBuilder) {}
53
54 fn display_name(&self) -> String;
56}
57
58#[derive(Clone)]
65pub struct ActionObject {
66 action: Arc<dyn Action>,
67 deps: Vec<ActionObject>,
68 id: Id
69}
70
71impl ActionObject {
72 pub fn new(action: Arc<dyn Action>) -> Self {
77 Self {
78 action,
79 deps: Vec::new(),
80 id: Id::default()
81 }
82 }
83
84 pub fn display_name(&self) -> String {
86 self.action.display_name()
87 }
88
89 pub(crate) fn id(&self) -> Id {
90 self.id
91 }
92
93 pub(crate) fn deps(&self) -> Vec<ActionObject> {
94 self.deps.clone()
95 }
96
97 pub(crate) async fn probe(&self, ctx: Runtime) -> Result<Probe, ActionError> {
98 self.action.probe(ctx).await
99 }
100
101 pub(crate) async fn run(&self, ctx: Runtime, operation: Operation) -> Result<Option<ActionOutput>, ActionError> {
102 self.action.run(ctx, operation).await
103 }
104
105 pub fn requires(&mut self, action: ActionObject) {
107 self.deps.push(action);
108 }
109
110 pub async fn load_state(&self, builder: &mut RuntimeBuilder) {
112 self.action.load_state(builder).await;
113 }
114}
115
116impl<A> From<A> for ActionObject
117where
118 A: Action + 'static
119{
120 fn from(action: A) -> Self {
121 Self::new(Arc::new(action))
122 }
123}
124
125#[derive(Default, Clone)]
130pub struct ContextCallbacks {
131 pub on_action_started: Option<fn(ActionObject)>,
133 pub on_action_finished: Option<fn(ActionObject)>,
135 pub on_action_failed: Option<fn(ActionObject, &ActionError)>
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
141pub struct Id(Uuid);
142
143impl Default for Id {
144 fn default() -> Self {
145 Self(Uuid::new_v4())
146 }
147}
148
149impl std::fmt::Display for Id {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 self.0.fmt(f)
152 }
153}
154
155#[derive(Debug, Clone)]
163pub enum ActionOutput {
164 String(String),
166 Integer(i64),
168 Float(f64),
170 Boolean(bool)
172}
173
174impl TryFrom<ActionOutput> for String {
175 type Error = ActionError;
176
177 fn try_from(value: ActionOutput) -> Result<Self, Self::Error> {
178 match value {
179 ActionOutput::String(value) => Ok(value),
180 _ => Err(ActionError::OutputConversionFailed("String".to_string()))
181 }
182 }
183}
184
185impl TryFrom<ActionOutput> for i64 {
186 type Error = ActionError;
187
188 fn try_from(value: ActionOutput) -> Result<Self, Self::Error> {
189 match value {
190 ActionOutput::Integer(value) => Ok(value),
191 _ => Err(ActionError::OutputConversionFailed("i64".to_string()))
192 }
193 }
194}
195
196impl TryFrom<ActionOutput> for f64 {
197 type Error = ActionError;
198
199 fn try_from(value: ActionOutput) -> Result<Self, Self::Error> {
200 match value {
201 ActionOutput::Float(value) => Ok(value),
202 _ => Err(ActionError::OutputConversionFailed("f64".to_string()))
203 }
204 }
205}
206
207impl TryFrom<ActionOutput> for bool {
208 type Error = ActionError;
209
210 fn try_from(value: ActionOutput) -> Result<Self, Self::Error> {
211 match value {
212 ActionOutput::Boolean(value) => Ok(value),
213 _ => Err(ActionError::OutputConversionFailed("bool".to_string()))
214 }
215 }
216}
217
218impl From<String> for ActionOutput {
219 fn from(value: String) -> Self {
220 Self::String(value)
221 }
222}
223
224impl From<i64> for ActionOutput {
225 fn from(value: i64) -> Self {
226 Self::Integer(value)
227 }
228}
229
230impl From<f64> for ActionOutput {
231 fn from(value: f64) -> Self {
232 Self::Float(value)
233 }
234}
235
236impl From<bool> for ActionOutput {
237 fn from(value: bool) -> Self {
238 Self::Boolean(value)
239 }
240}
241
242impl From<&str> for ActionOutput {
243 fn from(value: &str) -> Self {
244 Self::String(value.to_string())
245 }
246}
247
248pub enum ActionInput<T> {
255 Static(T),
257 Dynamic(ActionObject)
259}
260
261impl<T> ActionInput<T> {
262 pub fn new_dynamic(value: ActionObject) -> Self {
264 Self::Dynamic(value)
265 }
266
267 pub fn new_static(value: T) -> Self {
269 Self::Static(value)
270 }
271
272 pub fn static_value(&self) -> Option<&T> {
275 match self {
276 Self::Static(value) => Some(value),
277 _ => None
278 }
279 }
280
281 pub fn dynamic(&self) -> Option<ActionObject> {
284 match self {
285 Self::Dynamic(action) => Some(action.clone()),
286 _ => None
287 }
288 }
289
290 pub fn is_static(&self) -> bool {
292 self.static_value().is_some()
293 }
294
295 pub fn is_dynamic(&self) -> bool {
297 self.dynamic().is_some()
298 }
299
300 pub fn unwrap_static(&self) -> &T {
303 self.static_value().unwrap()
304 }
305
306 pub fn unwrap_dynamic(&self) -> ActionObject {
309 self.dynamic().unwrap()
310 }
311}
312
313impl<T> From<T> for ActionInput<T> {
314 fn from(value: T) -> Self {
315 Self::new_static(value)
316 }
317}
318
319impl<T: Default> Default for ActionInput<T> {
320 fn default() -> Self {
321 Self::new_static(T::default())
322 }
323}
324
325#[derive(Debug, Error, Clone)]
327#[non_exhaustive]
328pub enum ActionError {
329 #[error("{0}")]
331 ActionFailed(String, String),
332 #[error("Could not convert ActionOutput to {0}")]
334 OutputConversionFailed(String),
335 #[error("An internal error occured, please report this error code: {0}")]
337 InternalError(&'static str),
338 #[error("Dependency did not return a value")]
340 NoActionReturn,
341 #[error("Operation not supported")]
343 OperationNotSupported,
344 #[error("Required state was not loaded")]
346 StateNotLoaded
347}
348
349pub enum Operation {
356 Perform,
358 Rollback
360}
361
362#[derive(Debug, Clone)]
372pub struct Probe {
373 pub needs_run: bool,
375 pub can_rollback: bool
377}
378
379impl Default for Probe {
380 fn default() -> Self {
381 Self {
382 needs_run: true,
383 can_rollback: false
384 }
385 }
386}