Skip to main content

beetry_core/
task.rs

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
76/// User-provided task that defines work to be executed when ticking an
77/// action node.
78pub struct ActionTask {
79    task: BoxTaskFuture,
80    desc: TaskDescription,
81}
82
83impl ActionTask {
84    /// Creates an action task from a user-defined [`Task`] implementation.
85    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}