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    #[serde(rename = "watchdog")]
319    Watchdog,
320}
321
322impl TimerSchedulingMode {
323    #[must_use]
324    pub const fn label(self) -> &'static str {
325        match self {
326            Self::Once => "once",
327            Self::AfterCompletion => "after_completion",
328            Self::Deadline => "deadline",
329            Self::Retry => "retry",
330            Self::Continuation => "continuation",
331            Self::Watchdog => "watchdog",
332        }
333    }
334}
335
336///
337/// TimerExecutionOutcome
338///
339
340#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
341pub enum TimerExecutionOutcome {
342    #[serde(rename = "success")]
343    Success,
344    #[serde(rename = "no_work")]
345    NoWork,
346    #[serde(rename = "retryable_failure")]
347    RetryableFailure,
348    #[serde(rename = "invariant_failure")]
349    InvariantFailure,
350    #[serde(rename = "unacknowledged")]
351    Unacknowledged,
352}
353
354impl TimerExecutionOutcome {
355    #[must_use]
356    pub const fn label(self) -> &'static str {
357        match self {
358            Self::Success => "success",
359            Self::NoWork => "no_work",
360            Self::RetryableFailure => "retryable_failure",
361            Self::InvariantFailure => "invariant_failure",
362            Self::Unacknowledged => "unacknowledged",
363        }
364    }
365}
366
367#[cfg(test)]
368mod tests {
369    use super::*;
370
371    #[test]
372    fn runtime_enums_own_serialized_labels() {
373        assert_eq!(FailureSeverity::Info.label(), "info");
374        assert_eq!(FailureSeverity::Warning.label(), "warning");
375        assert_eq!(FailureSeverity::Error.label(), "error");
376        assert_eq!(FailureSeverity::Critical.label(), "critical");
377
378        assert_eq!(RuntimeFieldVisibility::PublicSafe.label(), "public_safe");
379        assert_eq!(
380            RuntimeFieldVisibility::OperatorOnly.label(),
381            "operator_only"
382        );
383        assert_eq!(
384            RuntimeFieldVisibility::ControllerOnly.label(),
385            "controller_only"
386        );
387        assert_eq!(
388            RuntimeFieldVisibility::FeatureGated.label(),
389            "feature_gated"
390        );
391        assert_eq!(RuntimeFieldVisibility::Disabled.label(), "disabled");
392
393        assert_eq!(RuntimeCheckStatus::Pass.label(), "pass");
394        assert_eq!(RuntimeCheckStatus::Warn.label(), "warn");
395        assert_eq!(RuntimeCheckStatus::Fail.label(), "fail");
396        assert_eq!(RuntimeCheckStatus::NotEvaluated.label(), "not_evaluated");
397
398        assert_eq!(RuntimeDiagnosticSeverity::Info.label(), "info");
399        assert_eq!(RuntimeDiagnosticSeverity::Warning.label(), "warning");
400        assert_eq!(RuntimeDiagnosticSeverity::Blocked.label(), "blocked");
401        assert_eq!(
402            RuntimeDiagnosticSeverity::Unsupported.label(),
403            "unsupported"
404        );
405
406        assert_eq!(RuntimeStateDomainStatus::Ok.label(), "ok");
407        assert_eq!(RuntimeStateDomainStatus::Warning.label(), "warning");
408        assert_eq!(RuntimeStateDomainStatus::Failing.label(), "failing");
409        assert_eq!(
410            RuntimeStateDomainStatus::NotEvaluated.label(),
411            "not_evaluated"
412        );
413
414        assert_eq!(HealthStatus::Healthy.label(), "healthy");
415        assert_eq!(HealthStatus::Degraded.label(), "degraded");
416        assert_eq!(HealthStatus::Unhealthy.label(), "unhealthy");
417        assert_eq!(HealthStatus::Unknown.label(), "unknown");
418
419        assert_eq!(ReadinessStatus::Ready.label(), "ready");
420        assert_eq!(ReadinessStatus::Degraded.label(), "degraded");
421        assert_eq!(ReadinessStatus::NotReady.label(), "not_ready");
422        assert_eq!(ReadinessStatus::NotEvaluated.label(), "not_evaluated");
423
424        assert_eq!(RuntimeStatus::Ok.label(), "ok");
425        assert_eq!(RuntimeStatus::Degraded.label(), "degraded");
426        assert_eq!(RuntimeStatus::Failing.label(), "failing");
427        assert_eq!(RuntimeStatus::Unknown.label(), "unknown");
428
429        assert_eq!(
430            TimerRegistrationStatus::Unregistered.label(),
431            "unregistered"
432        );
433        assert_eq!(TimerRegistrationStatus::Scheduled.label(), "scheduled");
434        assert_eq!(TimerRegistrationStatus::Running.label(), "running");
435
436        assert_eq!(TimerProcessCondition::Disabled.label(), "disabled");
437        assert_eq!(TimerProcessCondition::Idle.label(), "idle");
438        assert_eq!(TimerProcessCondition::Active.label(), "active");
439        assert_eq!(TimerProcessCondition::Retrying.label(), "retrying");
440        assert_eq!(TimerProcessCondition::Failed.label(), "failed");
441        assert_eq!(
442            TimerProcessCondition::MissingRegistration.label(),
443            "missing_registration"
444        );
445
446        assert_eq!(TimerSchedulingMode::Once.label(), "once");
447        assert_eq!(
448            TimerSchedulingMode::AfterCompletion.label(),
449            "after_completion"
450        );
451        assert_eq!(TimerSchedulingMode::Deadline.label(), "deadline");
452        assert_eq!(TimerSchedulingMode::Retry.label(), "retry");
453        assert_eq!(TimerSchedulingMode::Continuation.label(), "continuation");
454        assert_eq!(TimerSchedulingMode::Watchdog.label(), "watchdog");
455
456        assert_eq!(TimerExecutionOutcome::Success.label(), "success");
457        assert_eq!(TimerExecutionOutcome::NoWork.label(), "no_work");
458        assert_eq!(
459            TimerExecutionOutcome::RetryableFailure.label(),
460            "retryable_failure"
461        );
462        assert_eq!(
463            TimerExecutionOutcome::InvariantFailure.label(),
464            "invariant_failure"
465        );
466        assert_eq!(
467            TimerExecutionOutcome::Unacknowledged.label(),
468            "unacknowledged"
469        );
470    }
471}