Skip to main content

openvpn_mgmt_codec/
status_format.rs

1use std::fmt;
2use std::str::FromStr;
3
4/// Status output format version. Higher versions are more machine-parseable.
5///
6/// - V1: default human-readable format
7/// - V2: adds header/footer markers for easier parsing
8/// - V3: tab-delimited, ideal for programmatic consumption
9#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
10pub enum StatusFormat {
11    /// Default human-readable format.
12    #[default]
13    V1,
14
15    /// Adds header/footer markers for easier parsing.
16    V2,
17
18    /// Tab-delimited, ideal for programmatic consumption.
19    V3,
20}
21
22impl fmt::Display for StatusFormat {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        match self {
25            Self::V1 => f.write_str("1"),
26            Self::V2 => f.write_str("2"),
27            Self::V3 => f.write_str("3"),
28        }
29    }
30}
31
32impl FromStr for StatusFormat {
33    type Err = String;
34
35    /// Parse a status format version: `1`, `2`, or `3`.
36    fn from_str(s: &str) -> Result<Self, Self::Err> {
37        match s {
38            "1" => Ok(Self::V1),
39            "2" => Ok(Self::V2),
40            "3" => Ok(Self::V3),
41            _ => Err(format!("invalid status format: {s} (use 1, 2, or 3)")),
42        }
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn display_roundtrip() {
52        for fmt in [StatusFormat::V1, StatusFormat::V2, StatusFormat::V3] {
53            let s = fmt.to_string();
54            assert_eq!(s.parse::<StatusFormat>().unwrap(), fmt);
55        }
56    }
57
58    #[test]
59    fn display_values() {
60        assert_eq!(StatusFormat::V1.to_string(), "1");
61        assert_eq!(StatusFormat::V2.to_string(), "2");
62        assert_eq!(StatusFormat::V3.to_string(), "3");
63    }
64
65    #[test]
66    fn parse_invalid() {
67        assert!("4".parse::<StatusFormat>().is_err());
68        assert!("".parse::<StatusFormat>().is_err());
69    }
70}