Skip to main content

sara_core/model/
adr.rs

1//! ADR (Architecture Decision Record) lifecycle types.
2
3use std::fmt;
4use std::str::FromStr;
5
6use serde::{Deserialize, Serialize};
7
8/// Represents the lifecycle status of an ADR.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum AdrStatus {
12    /// Decision is under consideration, not yet finalized.
13    Proposed,
14    /// Decision has been approved and is in effect.
15    Accepted,
16    /// Decision is no longer recommended but not replaced.
17    Deprecated,
18    /// Decision has been replaced by a newer ADR.
19    Superseded,
20}
21
22impl AdrStatus {
23    /// Returns the display name for this status.
24    #[must_use]
25    pub const fn display_name(&self) -> &'static str {
26        match self {
27            Self::Proposed => "Proposed",
28            Self::Accepted => "Accepted",
29            Self::Deprecated => "Deprecated",
30            Self::Superseded => "Superseded",
31        }
32    }
33
34    /// Returns the YAML value (snake_case string) for this status.
35    #[must_use]
36    pub const fn as_str(&self) -> &'static str {
37        match self {
38            Self::Proposed => "proposed",
39            Self::Accepted => "accepted",
40            Self::Deprecated => "deprecated",
41            Self::Superseded => "superseded",
42        }
43    }
44}
45
46impl fmt::Display for AdrStatus {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        write!(f, "{}", self.display_name())
49    }
50}
51
52impl FromStr for AdrStatus {
53    type Err = String;
54
55    fn from_str(s: &str) -> Result<Self, Self::Err> {
56        match s.to_lowercase().as_str() {
57            "proposed" => Ok(Self::Proposed),
58            "accepted" => Ok(Self::Accepted),
59            "deprecated" => Ok(Self::Deprecated),
60            "superseded" => Ok(Self::Superseded),
61            _ => Err(format!(
62                "Invalid ADR status '{s}'. Expected one of: proposed, accepted, deprecated, superseded"
63            )),
64        }
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    fn test_adr_status_display() {
74        assert_eq!(AdrStatus::Proposed.to_string(), "Proposed");
75        assert_eq!(AdrStatus::Accepted.to_string(), "Accepted");
76        assert_eq!(AdrStatus::Deprecated.to_string(), "Deprecated");
77        assert_eq!(AdrStatus::Superseded.to_string(), "Superseded");
78    }
79
80    #[test]
81    fn test_adr_status_from_str() {
82        assert_eq!(
83            "proposed".parse::<AdrStatus>().unwrap(),
84            AdrStatus::Proposed
85        );
86        assert_eq!(
87            "ACCEPTED".parse::<AdrStatus>().unwrap(),
88            AdrStatus::Accepted
89        );
90        assert!("invalid".parse::<AdrStatus>().is_err());
91    }
92
93    #[test]
94    fn test_adr_status_as_str() {
95        assert_eq!(AdrStatus::Proposed.as_str(), "proposed");
96        assert_eq!(AdrStatus::Superseded.as_str(), "superseded");
97    }
98}