Skip to main content

canic_core/domain/
runtime.rs

1//! Module: domain::runtime
2//!
3//! Responsibility: define pure runtime value enums shared by runtime ops,
4//! status builders, and endpoint DTOs.
5//! Does not own: runtime status DTO structs, endpoint guards, or runtime
6//! mutation.
7//! Boundary: DTOs re-export these values to preserve the public API path while
8//! internal code imports them from the domain owner.
9
10use candid::CandidType;
11use serde::{Deserialize, Serialize};
12
13// CandidType supports explicit serde(rename) labels, but not rename_all. Keep
14// runtime introspection enum labels canonical and alias-free.
15
16///
17/// FailureSeverity
18///
19
20#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
21pub enum FailureSeverity {
22    #[serde(rename = "info")]
23    Info,
24    #[serde(rename = "warning")]
25    Warning,
26    #[serde(rename = "error")]
27    Error,
28    #[serde(rename = "critical")]
29    Critical,
30}
31
32impl FailureSeverity {
33    #[must_use]
34    pub const fn label(self) -> &'static str {
35        match self {
36            Self::Info => "info",
37            Self::Warning => "warning",
38            Self::Error => "error",
39            Self::Critical => "critical",
40        }
41    }
42}
43
44///
45/// RuntimeFieldVisibility
46///
47
48#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
49pub enum RuntimeFieldVisibility {
50    #[serde(rename = "public_safe")]
51    PublicSafe,
52    #[serde(rename = "operator_only")]
53    OperatorOnly,
54    #[serde(rename = "controller_only")]
55    ControllerOnly,
56    #[serde(rename = "feature_gated")]
57    FeatureGated,
58    #[serde(rename = "disabled")]
59    Disabled,
60}
61
62impl RuntimeFieldVisibility {
63    #[must_use]
64    pub const fn label(self) -> &'static str {
65        match self {
66            Self::PublicSafe => "public_safe",
67            Self::OperatorOnly => "operator_only",
68            Self::ControllerOnly => "controller_only",
69            Self::FeatureGated => "feature_gated",
70            Self::Disabled => "disabled",
71        }
72    }
73}
74
75///
76/// RuntimeCheckStatus
77///
78
79#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
80pub enum RuntimeCheckStatus {
81    #[serde(rename = "pass")]
82    Pass,
83    #[serde(rename = "warn")]
84    Warn,
85    #[serde(rename = "fail")]
86    Fail,
87    #[serde(rename = "not_evaluated")]
88    NotEvaluated,
89}
90
91impl RuntimeCheckStatus {
92    #[must_use]
93    pub const fn label(self) -> &'static str {
94        match self {
95            Self::Pass => "pass",
96            Self::Warn => "warn",
97            Self::Fail => "fail",
98            Self::NotEvaluated => "not_evaluated",
99        }
100    }
101}
102
103///
104/// RuntimeDiagnosticSeverity
105///
106
107#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
108pub enum RuntimeDiagnosticSeverity {
109    #[serde(rename = "info")]
110    Info,
111    #[serde(rename = "warning")]
112    Warning,
113    #[serde(rename = "blocked")]
114    Blocked,
115    #[serde(rename = "unsupported")]
116    Unsupported,
117}
118
119impl RuntimeDiagnosticSeverity {
120    #[must_use]
121    pub const fn label(self) -> &'static str {
122        match self {
123            Self::Info => "info",
124            Self::Warning => "warning",
125            Self::Blocked => "blocked",
126            Self::Unsupported => "unsupported",
127        }
128    }
129}
130
131///
132/// RuntimeStateDomainStatus
133///
134
135#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
136pub enum RuntimeStateDomainStatus {
137    #[serde(rename = "ok")]
138    Ok,
139    #[serde(rename = "warning")]
140    Warning,
141    #[serde(rename = "failing")]
142    Failing,
143    #[serde(rename = "not_evaluated")]
144    NotEvaluated,
145}
146
147impl RuntimeStateDomainStatus {
148    #[must_use]
149    pub const fn label(self) -> &'static str {
150        match self {
151            Self::Ok => "ok",
152            Self::Warning => "warning",
153            Self::Failing => "failing",
154            Self::NotEvaluated => "not_evaluated",
155        }
156    }
157}
158
159///
160/// HealthStatus
161///
162
163#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
164pub enum HealthStatus {
165    #[serde(rename = "healthy")]
166    Healthy,
167    #[serde(rename = "degraded")]
168    Degraded,
169    #[serde(rename = "unhealthy")]
170    Unhealthy,
171    #[serde(rename = "unknown")]
172    Unknown,
173}
174
175impl HealthStatus {
176    #[must_use]
177    pub const fn label(self) -> &'static str {
178        match self {
179            Self::Healthy => "healthy",
180            Self::Degraded => "degraded",
181            Self::Unhealthy => "unhealthy",
182            Self::Unknown => "unknown",
183        }
184    }
185}
186
187///
188/// ReadinessStatus
189///
190
191#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
192pub enum ReadinessStatus {
193    #[serde(rename = "ready")]
194    Ready,
195    #[serde(rename = "degraded")]
196    Degraded,
197    #[serde(rename = "not_ready")]
198    NotReady,
199    #[serde(rename = "not_evaluated")]
200    NotEvaluated,
201}
202
203impl ReadinessStatus {
204    #[must_use]
205    pub const fn label(self) -> &'static str {
206        match self {
207            Self::Ready => "ready",
208            Self::Degraded => "degraded",
209            Self::NotReady => "not_ready",
210            Self::NotEvaluated => "not_evaluated",
211        }
212    }
213}
214
215///
216/// RuntimeStatus
217///
218
219#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
220pub enum RuntimeStatus {
221    #[serde(rename = "ok")]
222    Ok,
223    #[serde(rename = "degraded")]
224    Degraded,
225    #[serde(rename = "failing")]
226    Failing,
227    #[serde(rename = "unknown")]
228    Unknown,
229}
230
231impl RuntimeStatus {
232    #[must_use]
233    pub const fn label(self) -> &'static str {
234        match self {
235            Self::Ok => "ok",
236            Self::Degraded => "degraded",
237            Self::Failing => "failing",
238            Self::Unknown => "unknown",
239        }
240    }
241}
242
243///
244/// TimerRegistrationStatus
245///
246
247#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
248pub enum TimerRegistrationStatus {
249    #[serde(rename = "unregistered")]
250    Unregistered,
251    #[serde(rename = "scheduled")]
252    Scheduled,
253    #[serde(rename = "running")]
254    Running,
255}
256
257impl TimerRegistrationStatus {
258    #[must_use]
259    pub const fn label(self) -> &'static str {
260        match self {
261            Self::Unregistered => "unregistered",
262            Self::Scheduled => "scheduled",
263            Self::Running => "running",
264        }
265    }
266}
267
268///
269/// TimerProcessCondition
270///
271
272#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
273pub enum TimerProcessCondition {
274    #[serde(rename = "disabled")]
275    Disabled,
276    #[serde(rename = "idle")]
277    Idle,
278    #[serde(rename = "active")]
279    Active,
280    #[serde(rename = "retrying")]
281    Retrying,
282    #[serde(rename = "failed")]
283    Failed,
284    #[serde(rename = "missing_registration")]
285    MissingRegistration,
286}
287
288impl TimerProcessCondition {
289    #[must_use]
290    pub const fn label(self) -> &'static str {
291        match self {
292            Self::Disabled => "disabled",
293            Self::Idle => "idle",
294            Self::Active => "active",
295            Self::Retrying => "retrying",
296            Self::Failed => "failed",
297            Self::MissingRegistration => "missing_registration",
298        }
299    }
300}
301
302///
303/// TimerSchedulingMode
304///
305
306#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
307pub enum TimerSchedulingMode {
308    #[serde(rename = "once")]
309    Once,
310    #[serde(rename = "after_completion")]
311    AfterCompletion,
312    #[serde(rename = "deadline")]
313    Deadline,
314    #[serde(rename = "retry")]
315    Retry,
316    #[serde(rename = "continuation")]
317    Continuation,
318}
319
320impl TimerSchedulingMode {
321    #[must_use]
322    pub const fn label(self) -> &'static str {
323        match self {
324            Self::Once => "once",
325            Self::AfterCompletion => "after_completion",
326            Self::Deadline => "deadline",
327            Self::Retry => "retry",
328            Self::Continuation => "continuation",
329        }
330    }
331}
332
333///
334/// TimerExecutionOutcome
335///
336
337#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
338pub enum TimerExecutionOutcome {
339    #[serde(rename = "success")]
340    Success,
341    #[serde(rename = "no_work")]
342    NoWork,
343    #[serde(rename = "retryable_failure")]
344    RetryableFailure,
345    #[serde(rename = "invariant_failure")]
346    InvariantFailure,
347}
348
349impl TimerExecutionOutcome {
350    #[must_use]
351    pub const fn label(self) -> &'static str {
352        match self {
353            Self::Success => "success",
354            Self::NoWork => "no_work",
355            Self::RetryableFailure => "retryable_failure",
356            Self::InvariantFailure => "invariant_failure",
357        }
358    }
359}
360
361///
362/// TimerMode
363///
364
365#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
366#[remain::sorted]
367pub enum TimerMode {
368    Interval,
369    Once,
370}
371
372#[cfg(test)]
373mod tests {
374    use super::*;
375
376    #[test]
377    fn runtime_enums_own_serialized_labels() {
378        assert_eq!(FailureSeverity::Info.label(), "info");
379        assert_eq!(FailureSeverity::Warning.label(), "warning");
380        assert_eq!(FailureSeverity::Error.label(), "error");
381        assert_eq!(FailureSeverity::Critical.label(), "critical");
382
383        assert_eq!(RuntimeFieldVisibility::PublicSafe.label(), "public_safe");
384        assert_eq!(
385            RuntimeFieldVisibility::OperatorOnly.label(),
386            "operator_only"
387        );
388        assert_eq!(
389            RuntimeFieldVisibility::ControllerOnly.label(),
390            "controller_only"
391        );
392        assert_eq!(
393            RuntimeFieldVisibility::FeatureGated.label(),
394            "feature_gated"
395        );
396        assert_eq!(RuntimeFieldVisibility::Disabled.label(), "disabled");
397
398        assert_eq!(RuntimeCheckStatus::Pass.label(), "pass");
399        assert_eq!(RuntimeCheckStatus::Warn.label(), "warn");
400        assert_eq!(RuntimeCheckStatus::Fail.label(), "fail");
401        assert_eq!(RuntimeCheckStatus::NotEvaluated.label(), "not_evaluated");
402
403        assert_eq!(RuntimeDiagnosticSeverity::Info.label(), "info");
404        assert_eq!(RuntimeDiagnosticSeverity::Warning.label(), "warning");
405        assert_eq!(RuntimeDiagnosticSeverity::Blocked.label(), "blocked");
406        assert_eq!(
407            RuntimeDiagnosticSeverity::Unsupported.label(),
408            "unsupported"
409        );
410
411        assert_eq!(RuntimeStateDomainStatus::Ok.label(), "ok");
412        assert_eq!(RuntimeStateDomainStatus::Warning.label(), "warning");
413        assert_eq!(RuntimeStateDomainStatus::Failing.label(), "failing");
414        assert_eq!(
415            RuntimeStateDomainStatus::NotEvaluated.label(),
416            "not_evaluated"
417        );
418
419        assert_eq!(HealthStatus::Healthy.label(), "healthy");
420        assert_eq!(HealthStatus::Degraded.label(), "degraded");
421        assert_eq!(HealthStatus::Unhealthy.label(), "unhealthy");
422        assert_eq!(HealthStatus::Unknown.label(), "unknown");
423
424        assert_eq!(ReadinessStatus::Ready.label(), "ready");
425        assert_eq!(ReadinessStatus::Degraded.label(), "degraded");
426        assert_eq!(ReadinessStatus::NotReady.label(), "not_ready");
427        assert_eq!(ReadinessStatus::NotEvaluated.label(), "not_evaluated");
428
429        assert_eq!(RuntimeStatus::Ok.label(), "ok");
430        assert_eq!(RuntimeStatus::Degraded.label(), "degraded");
431        assert_eq!(RuntimeStatus::Failing.label(), "failing");
432        assert_eq!(RuntimeStatus::Unknown.label(), "unknown");
433
434        assert_eq!(
435            TimerRegistrationStatus::Unregistered.label(),
436            "unregistered"
437        );
438        assert_eq!(TimerRegistrationStatus::Scheduled.label(), "scheduled");
439        assert_eq!(TimerRegistrationStatus::Running.label(), "running");
440
441        assert_eq!(TimerProcessCondition::Disabled.label(), "disabled");
442        assert_eq!(TimerProcessCondition::Idle.label(), "idle");
443        assert_eq!(TimerProcessCondition::Active.label(), "active");
444        assert_eq!(TimerProcessCondition::Retrying.label(), "retrying");
445        assert_eq!(TimerProcessCondition::Failed.label(), "failed");
446        assert_eq!(
447            TimerProcessCondition::MissingRegistration.label(),
448            "missing_registration"
449        );
450
451        assert_eq!(TimerSchedulingMode::Once.label(), "once");
452        assert_eq!(
453            TimerSchedulingMode::AfterCompletion.label(),
454            "after_completion"
455        );
456        assert_eq!(TimerSchedulingMode::Deadline.label(), "deadline");
457        assert_eq!(TimerSchedulingMode::Retry.label(), "retry");
458        assert_eq!(TimerSchedulingMode::Continuation.label(), "continuation");
459
460        assert_eq!(TimerExecutionOutcome::Success.label(), "success");
461        assert_eq!(TimerExecutionOutcome::NoWork.label(), "no_work");
462        assert_eq!(
463            TimerExecutionOutcome::RetryableFailure.label(),
464            "retryable_failure"
465        );
466        assert_eq!(
467            TimerExecutionOutcome::InvariantFailure.label(),
468            "invariant_failure"
469        );
470    }
471}