Skip to main content

sara_core/model/
adr.rs

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