Skip to main content

openvpn_mgmt_codec/
stream_mode.rs

1use std::fmt;
2use std::str::FromStr;
3
4/// Error returned when a string is not a recognized stream mode.
5#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
6#[error("unrecognized stream mode: {0:?}")]
7pub struct ParseStreamModeError(pub String);
8
9/// Mode selector for commands that share the on/off/all/on-all/N grammar.
10/// This is used by `log`, `state`, and `echo`, all of which support
11/// identical sub-commands.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum StreamMode {
14    /// Enable real-time notifications.
15    On,
16
17    /// Disable real-time notifications.
18    Off,
19
20    /// Dump the entire history buffer.
21    All,
22
23    /// Atomically enable real-time notifications AND dump history.
24    /// This guarantees no messages are missed between the dump and
25    /// the start of real-time streaming.
26    OnAll,
27
28    /// Show the N most recent history entries.
29    Recent(u32),
30}
31
32impl fmt::Display for StreamMode {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        match self {
35            Self::On => f.write_str("on"),
36            Self::Off => f.write_str("off"),
37            Self::All => f.write_str("all"),
38            Self::OnAll => f.write_str("on all"),
39            Self::Recent(n) => write!(f, "{n}"),
40        }
41    }
42}
43
44impl FromStr for StreamMode {
45    type Err = ParseStreamModeError;
46
47    /// Parse a stream mode string: `on`, `off`, `all`, `on all`, or a number.
48    fn from_str(s: &str) -> Result<Self, Self::Err> {
49        match s {
50            "on" => Ok(Self::On),
51            "off" => Ok(Self::Off),
52            "all" => Ok(Self::All),
53            "on all" => Ok(Self::OnAll),
54            n => n
55                .parse::<u32>()
56                .map(Self::Recent)
57                .map_err(|_| ParseStreamModeError(s.to_string())),
58        }
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn parse_roundtrip() {
68        for mode in [
69            StreamMode::On,
70            StreamMode::Off,
71            StreamMode::All,
72            StreamMode::OnAll,
73            StreamMode::Recent(42),
74        ] {
75            let s = mode.to_string();
76            assert_eq!(s.parse::<StreamMode>().unwrap(), mode);
77        }
78    }
79
80    #[test]
81    fn parse_invalid() {
82        assert!("bogus".parse::<StreamMode>().is_err());
83    }
84}