Skip to main content

harmos_domain/operations/common/
instance.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10// Portable identity, status and handle contract of one submitted operation.
11// Every host binding reports the same status projection; the in-process
12// manager keeps its richer status alongside it.
13
14/* === Modules === */
15
16/* === Re-Exports === */
17
18/* === Imports === */
19
20// Standard Library Imports
21use std::fmt;
22use std::str::FromStr;
23
24// Third Party Imports
25use serde::{Deserialize, Serialize};
26
27// Local Imports
28
29/* === Constants === */
30
31/* === Macros === */
32
33/* === Type Aliases === */
34
35/* === Structs === */
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
38#[serde(transparent)]
39pub struct Id(u64);
40
41#[derive(Clone, Copy, Debug, PartialEq, Eq)]
42pub struct Status {
43    pub phase: Phase,
44    pub outcome: Option<Outcome>,
45    pub cancellation_requested: bool,
46    pub attempt: u32,
47}
48
49/* === Enums === */
50
51// Resident phases are reserved for long-running declarations; request-scoped
52// operations never report them.
53#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
54#[serde(rename_all = "snake_case")]
55pub enum Phase {
56    Queued,
57    Initializing,
58    Running,
59    RetryWaiting,
60    Restarting,
61    Stopping,
62    CleaningUp,
63    Stopped,
64    Settled,
65}
66
67#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
68#[serde(rename_all = "snake_case")]
69pub enum Outcome {
70    Succeeded,
71    Failed,
72    Cancelled,
73    TimedOut,
74    Unavailable,
75}
76
77#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
78#[error("unknown operation instance {kind} `{value}`")]
79pub struct ParseError {
80    kind: &'static str,
81    value: String,
82}
83
84/* === Traits === */
85
86/* === Implementations === */
87
88impl Id {
89    pub const fn new(value: u64) -> Self {
90        Self(value)
91    }
92
93    pub const fn value(self) -> u64 {
94        self.0
95    }
96}
97
98impl fmt::Display for Id {
99    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
100        self.0.fmt(formatter)
101    }
102}
103
104impl Status {
105    pub fn is_settled(&self) -> bool {
106        matches!(self.phase, Phase::Settled | Phase::Stopped)
107    }
108}
109
110impl Phase {
111    pub const fn as_str(self) -> &'static str {
112        match self {
113            Self::Queued => "queued",
114            Self::Initializing => "initializing",
115            Self::Running => "running",
116            Self::RetryWaiting => "retry_waiting",
117            Self::Restarting => "restarting",
118            Self::Stopping => "stopping",
119            Self::CleaningUp => "cleaning_up",
120            Self::Stopped => "stopped",
121            Self::Settled => "settled",
122        }
123    }
124}
125
126impl FromStr for Phase {
127    type Err = ParseError;
128
129    fn from_str(value: &str) -> Result<Self, ParseError> {
130        let phase = match value {
131            "queued" => Self::Queued,
132            "initializing" => Self::Initializing,
133            "running" => Self::Running,
134            "retry_waiting" => Self::RetryWaiting,
135            "restarting" => Self::Restarting,
136            "stopping" => Self::Stopping,
137            "cleaning_up" => Self::CleaningUp,
138            "stopped" => Self::Stopped,
139            "settled" => Self::Settled,
140            _ => {
141                return Err(ParseError { kind: "phase", value: value.to_owned() });
142            }
143        };
144        Ok(phase)
145    }
146}
147
148impl Outcome {
149    pub const fn as_str(self) -> &'static str {
150        match self {
151            Self::Succeeded => "succeeded",
152            Self::Failed => "failed",
153            Self::Cancelled => "cancelled",
154            Self::TimedOut => "timed_out",
155            Self::Unavailable => "unavailable",
156        }
157    }
158}
159
160impl FromStr for Outcome {
161    type Err = ParseError;
162
163    fn from_str(value: &str) -> Result<Self, ParseError> {
164        let outcome = match value {
165            "succeeded" => Self::Succeeded,
166            "failed" => Self::Failed,
167            "cancelled" => Self::Cancelled,
168            "timed_out" => Self::TimedOut,
169            "unavailable" => Self::Unavailable,
170            _ => {
171                return Err(ParseError { kind: "outcome", value: value.to_owned() });
172            }
173        };
174        Ok(outcome)
175    }
176}
177
178/* === Public Functions === */
179
180/* === Private Functions === */
181
182/* === Tests === */