Skip to main content

higher_graphen_core/
review.rs

1use crate::{CoreError, Result};
2use serde::{Deserialize, Serialize};
3use std::fmt;
4use std::str::FromStr;
5
6/// Impact classification used by downstream model and engine crates.
7#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
8#[serde(rename_all = "snake_case")]
9pub enum Severity {
10    /// Lowest impact classification.
11    Low,
12    /// Moderate impact classification.
13    Medium,
14    /// High impact classification.
15    High,
16    /// Highest impact classification.
17    Critical,
18}
19
20impl Severity {
21    /// Stable lower snake case representation used by serde and text protocols.
22    pub fn as_str(self) -> &'static str {
23        match self {
24            Self::Low => "low",
25            Self::Medium => "medium",
26            Self::High => "high",
27            Self::Critical => "critical",
28        }
29    }
30
31    /// Returns true when this severity is at least the supplied minimum.
32    pub fn is_at_least(self, minimum: Self) -> bool {
33        self >= minimum
34    }
35}
36
37impl FromStr for Severity {
38    type Err = CoreError;
39
40    fn from_str(value: &str) -> Result<Self> {
41        match value {
42            "low" => Ok(Self::Low),
43            "medium" => Ok(Self::Medium),
44            "high" => Ok(Self::High),
45            "critical" => Ok(Self::Critical),
46            unknown => Err(CoreError::parse_failure(
47                "severity",
48                unknown,
49                "expected low, medium, high, or critical",
50            )),
51        }
52    }
53}
54
55impl TryFrom<&str> for Severity {
56    type Error = CoreError;
57
58    fn try_from(value: &str) -> Result<Self> {
59        Self::from_str(value)
60    }
61}
62
63impl TryFrom<String> for Severity {
64    type Error = CoreError;
65
66    fn try_from(value: String) -> Result<Self> {
67        Self::from_str(&value)
68    }
69}
70
71impl fmt::Display for Severity {
72    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
73        formatter.write_str(self.as_str())
74    }
75}
76
77/// Human or workflow review state for observed or inferred structure.
78#[derive(
79    Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
80)]
81#[serde(rename_all = "snake_case")]
82pub enum ReviewStatus {
83    /// Candidate structure inferred or generated but not yet confirmed.
84    Candidate,
85    /// No review has occurred.
86    #[default]
87    Unreviewed,
88    /// Review occurred without accepting or rejecting the structure.
89    Reviewed,
90    /// The structure must not be treated as accepted fact.
91    Rejected,
92    /// The structure may be treated as accepted fact.
93    Accepted,
94}
95
96impl ReviewStatus {
97    /// Stable lower snake case representation used by serde and text protocols.
98    pub fn as_str(self) -> &'static str {
99        match self {
100            Self::Candidate => "candidate",
101            Self::Unreviewed => "unreviewed",
102            Self::Reviewed => "reviewed",
103            Self::Rejected => "rejected",
104            Self::Accepted => "accepted",
105        }
106    }
107
108    /// Returns true when the structure may be treated as accepted fact.
109    pub fn is_accepted(self) -> bool {
110        matches!(self, Self::Accepted)
111    }
112
113    /// Returns true when the structure must not be silently promoted.
114    pub fn is_rejected(self) -> bool {
115        matches!(self, Self::Rejected)
116    }
117
118    /// Returns true when a review action has occurred.
119    pub fn has_review_action(self) -> bool {
120        !matches!(self, Self::Candidate | Self::Unreviewed)
121    }
122}
123
124impl FromStr for ReviewStatus {
125    type Err = CoreError;
126
127    fn from_str(value: &str) -> Result<Self> {
128        match value {
129            "candidate" => Ok(Self::Candidate),
130            "unreviewed" => Ok(Self::Unreviewed),
131            "reviewed" => Ok(Self::Reviewed),
132            "rejected" => Ok(Self::Rejected),
133            "accepted" => Ok(Self::Accepted),
134            unknown => Err(CoreError::parse_failure(
135                "review_status",
136                unknown,
137                "expected candidate, unreviewed, reviewed, rejected, or accepted",
138            )),
139        }
140    }
141}
142
143impl TryFrom<&str> for ReviewStatus {
144    type Error = CoreError;
145
146    fn try_from(value: &str) -> Result<Self> {
147        Self::from_str(value)
148    }
149}
150
151impl TryFrom<String> for ReviewStatus {
152    type Error = CoreError;
153
154    fn try_from(value: String) -> Result<Self> {
155        Self::from_str(&value)
156    }
157}
158
159impl fmt::Display for ReviewStatus {
160    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
161        formatter.write_str(self.as_str())
162    }
163}