Skip to main content

ralph/contracts/task/
priority.rs

1//! Purpose: Define task-priority ordering, formatting, and parsing helpers.
2//!
3//! Responsibilities:
4//! - Define `TaskPriority`.
5//! - Provide ordering/weight/cycle helpers.
6//! - Provide `Display` and `FromStr` support.
7//!
8//! Scope:
9//! - Priority behavior only; task/task-agent data models and serde/schema
10//!   helpers live in sibling modules.
11//!
12//! Usage:
13//! - Used by task contracts and queue sorting through `crate::contracts`.
14//!
15//! Invariants/Assumptions:
16//! - Ordering remains critical > high > medium > low.
17//! - String parsing stays case-insensitive with canonical lowercase output.
18
19use std::str::FromStr;
20
21use anyhow::{Result, bail};
22use schemars::JsonSchema;
23use serde::{Deserialize, Serialize};
24
25/// Task priority used for queue ordering and display.
26#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, Default, JsonSchema)]
27#[serde(rename_all = "snake_case")]
28pub enum TaskPriority {
29    Critical,
30    High,
31    #[default]
32    Medium,
33    Low,
34}
35
36impl PartialOrd for TaskPriority {
37    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
38        Some(self.cmp(other))
39    }
40}
41
42impl Ord for TaskPriority {
43    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
44        self.weight().cmp(&other.weight())
45    }
46}
47
48impl TaskPriority {
49    pub fn as_str(self) -> &'static str {
50        match self {
51            TaskPriority::Critical => "critical",
52            TaskPriority::High => "high",
53            TaskPriority::Medium => "medium",
54            TaskPriority::Low => "low",
55        }
56    }
57
58    pub fn weight(self) -> u8 {
59        match self {
60            TaskPriority::Critical => 3,
61            TaskPriority::High => 2,
62            TaskPriority::Medium => 1,
63            TaskPriority::Low => 0,
64        }
65    }
66
67    /// Cycle to the next priority in ascending order, wrapping after Critical.
68    pub fn cycle(self) -> Self {
69        match self {
70            TaskPriority::Low => TaskPriority::Medium,
71            TaskPriority::Medium => TaskPriority::High,
72            TaskPriority::High => TaskPriority::Critical,
73            TaskPriority::Critical => TaskPriority::Low,
74        }
75    }
76}
77
78impl std::fmt::Display for TaskPriority {
79    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        f.write_str(self.as_str())
81    }
82}
83
84impl FromStr for TaskPriority {
85    type Err = anyhow::Error;
86
87    fn from_str(value: &str) -> Result<Self> {
88        let token = value.trim();
89
90        if token.eq_ignore_ascii_case("critical") {
91            return Ok(TaskPriority::Critical);
92        }
93        if token.eq_ignore_ascii_case("high") {
94            return Ok(TaskPriority::High);
95        }
96        if token.eq_ignore_ascii_case("medium") {
97            return Ok(TaskPriority::Medium);
98        }
99        if token.eq_ignore_ascii_case("low") {
100            return Ok(TaskPriority::Low);
101        }
102
103        bail!(
104            "Invalid priority: '{}'. Expected one of: critical, high, medium, low.",
105            token
106        )
107    }
108}