1mod execution;
2
3use std::{pin::Pin, str::FromStr};
4
5use anyhow::{Error, Result, anyhow};
6#[cfg(test)]
7pub use execution::MockRegisterTask;
8pub use execution::{AbortTask, ExecutorConcept, QueryTask, RegisterTask, TaskHandle};
9
10use crate::TickStatus;
11
12pub trait Task {
13 fn run(self) -> impl Future<Output = TickStatus> + Send + 'static;
14 fn task_desc(&self) -> TaskDescription {
15 TaskDescription::from_str(std::any::type_name::<Self>()).unwrap()
16 }
17}
18
19#[derive(Debug, Clone)]
20pub struct TaskDescription {
21 desc: String,
22}
23
24impl FromStr for TaskDescription {
25 type Err = Error;
26 fn from_str(s: &str) -> Result<Self, Self::Err> {
27 Ok(Self { desc: s.into() })
28 }
29}
30
31impl std::fmt::Display for TaskDescription {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 write!(f, "{}", self.desc)
34 }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum TaskStatus {
39 Success,
40 Running,
41 Failure,
42 Aborted,
43}
44
45impl TaskStatus {
46 #[must_use]
47 pub fn is_terminal(&self) -> bool {
48 matches!(self, Self::Success | Self::Failure | Self::Aborted)
49 }
50}
51
52impl From<TickStatus> for TaskStatus {
53 fn from(value: TickStatus) -> Self {
54 match value {
55 TickStatus::Success => Self::Success,
56 TickStatus::Running => Self::Running,
57 TickStatus::Failure => Self::Failure,
58 }
59 }
60}
61
62impl TryFrom<TaskStatus> for TickStatus {
63 type Error = Error;
64 fn try_from(value: TaskStatus) -> Result<Self, Self::Error> {
65 match value {
66 TaskStatus::Success => Ok(Self::Success),
67 TaskStatus::Running => Ok(Self::Running),
68 TaskStatus::Failure => Ok(Self::Failure),
69 TaskStatus::Aborted => Err(anyhow!("expected tree status subset of task status")),
70 }
71 }
72}
73
74pub type BoxTaskFuture = Box<dyn Future<Output = TickStatus> + Send + 'static>;
75
76pub struct ActionTask {
79 task: BoxTaskFuture,
80 desc: TaskDescription,
81}
82
83impl ActionTask {
84 pub fn new(task: impl Task) -> Self {
86 let desc = task.task_desc();
87 let task = Box::new(task.run());
88
89 Self { task, desc }
90 }
91
92 pub fn desc(&self) -> &TaskDescription {
93 &self.desc
94 }
95
96 pub async fn execute(self) -> TickStatus {
97 let fut = Pin::from(self.task);
98 fut.await
99 }
100}