1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
7#[serde(rename_all = "snake_case")]
8#[non_exhaustive]
9pub enum WorkloadState {
10 Created,
12 Running,
14 Stopped,
16 Completed,
18 Error,
20 Restarting,
22 #[default]
24 Unknown,
25 NotFound,
27}
28
29impl WorkloadState {
30 #[must_use]
32 pub const fn is_running(self) -> bool {
33 matches!(self, Self::Running)
34 }
35
36 #[must_use]
38 pub const fn is_terminal(self) -> bool {
39 matches!(
40 self,
41 Self::Stopped | Self::Completed | Self::Error | Self::NotFound
42 )
43 }
44
45 #[must_use]
47 pub const fn as_str(self) -> &'static str {
48 match self {
49 Self::Created => "created",
50 Self::Running => "running",
51 Self::Stopped => "stopped",
52 Self::Completed => "completed",
53 Self::Error => "error",
54 Self::Restarting => "restarting",
55 Self::Unknown => "unknown",
56 Self::NotFound => "not_found",
57 }
58 }
59}
60
61impl std::fmt::Display for WorkloadState {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 f.write_str(self.as_str())
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
69#[serde(rename_all = "kebab-case")]
70#[non_exhaustive]
71pub enum RestartPolicy {
72 #[default]
74 No,
75 Always,
77 OnFailure,
79 UnlessStopped,
81}
82
83impl RestartPolicy {
84 #[must_use]
86 pub const fn as_str(self) -> &'static str {
87 match self {
88 Self::No => "no",
89 Self::Always => "always",
90 Self::OnFailure => "on-failure",
91 Self::UnlessStopped => "unless-stopped",
92 }
93 }
94}
95
96impl std::fmt::Display for RestartPolicy {
97 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98 f.write_str(self.as_str())
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn state_default_is_unknown() {
108 assert_eq!(WorkloadState::default(), WorkloadState::Unknown);
109 }
110
111 #[test]
112 fn state_running_and_terminal_classification() {
113 assert!(WorkloadState::Running.is_running());
114 assert!(!WorkloadState::Running.is_terminal());
115 assert!(WorkloadState::Completed.is_terminal());
116 assert!(WorkloadState::Error.is_terminal());
117 assert!(!WorkloadState::Created.is_terminal());
118 }
119
120 #[test]
121 fn state_as_str_covers_every_variant() {
122 assert_eq!(WorkloadState::Created.as_str(), "created");
123 assert_eq!(WorkloadState::Running.as_str(), "running");
124 assert_eq!(WorkloadState::Stopped.as_str(), "stopped");
125 assert_eq!(WorkloadState::Completed.as_str(), "completed");
126 assert_eq!(WorkloadState::Error.as_str(), "error");
127 assert_eq!(WorkloadState::Restarting.as_str(), "restarting");
128 assert_eq!(WorkloadState::Unknown.as_str(), "unknown");
129 assert_eq!(WorkloadState::NotFound.as_str(), "not_found");
130 }
131
132 #[test]
133 fn state_display_matches_as_str() {
134 assert_eq!(WorkloadState::NotFound.to_string(), "not_found");
135 assert_eq!(WorkloadState::Restarting.as_str(), "restarting");
136 }
137
138 #[test]
139 fn state_serializes_snake_case() {
140 let json = serde_json::to_string(&WorkloadState::NotFound).unwrap();
141 assert_eq!(json, "\"not_found\"");
142 }
143
144 #[test]
145 fn restart_policy_default_is_no() {
146 assert_eq!(RestartPolicy::default(), RestartPolicy::No);
147 }
148
149 #[test]
150 fn restart_policy_as_str_covers_every_variant() {
151 assert_eq!(RestartPolicy::No.as_str(), "no");
152 assert_eq!(RestartPolicy::Always.as_str(), "always");
153 assert_eq!(RestartPolicy::OnFailure.as_str(), "on-failure");
154 assert_eq!(RestartPolicy::UnlessStopped.as_str(), "unless-stopped");
155 }
156
157 #[test]
158 fn restart_policy_display_uses_kebab_case() {
159 assert_eq!(RestartPolicy::OnFailure.to_string(), "on-failure");
160 assert_eq!(RestartPolicy::UnlessStopped.as_str(), "unless-stopped");
161 }
162
163 #[test]
164 fn restart_policy_serializes_kebab_case() {
165 let json = serde_json::to_string(&RestartPolicy::OnFailure).unwrap();
166 assert_eq!(json, "\"on-failure\"");
167 }
168}