ping_command/
round_trip_statistics.rs

1//! Ping command round trip metrics.
2//! 
3//! Example:
4//! 
5//! ```
6//! use ping_command::round_trip_statistics::RoundTripStatistics;
7//! let round_trip_statistics = RoundTripStatistics {
8//!     min: 12.445,
9//!     max: 61.365,
10//!     average: 26.791,
11//!     standard_deviation: 20.049,
12//! };
13//! assert_eq!(round_trip_statistics.min, 12.445);
14//! assert_eq!(round_trip_statistics.max, 61.365);
15//! assert_eq!(round_trip_statistics.average, 26.791);
16//! assert_eq!(round_trip_statistics.standard_deviation, 20.049);
17//! ```
18
19#[derive(Debug, Clone, Copy)]
20pub struct RoundTripStatistics {
21    pub min: f64,
22    pub max: f64,
23    pub average: f64,
24    pub standard_deviation: f64,
25}
26
27impl std::fmt::Display for RoundTripStatistics {
28
29    /// Format the RoundTripStatistics for Display.
30    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
31        write!(
32            f, 
33            concat!(
34                "min: {:.3}\n",
35                "max: {:.3}\n",
36                "average: {:.3}\n",
37                "standard deviation: {:.3}",
38            ),
39            self.min,
40            self.max,
41            self.average,
42            self.standard_deviation,
43        )
44    }
45}
46
47#[derive(Debug, PartialEq, Eq)]
48pub struct ParseError;
49
50impl std::str::FromStr for RoundTripStatistics {
51    type Err = ParseError;
52
53    /// Parse the ping standard output string round trip metrics into milliseconds as f64 floats.
54    /// 
55    /// Example:
56    /// 
57    /// ```nodoc
58    /// use std::str::FromStr;
59    /// use ping_command::round_trip_statistics::RoundTripStatistics;
60    /// let str = "round-trip min/avg/max/stddev = 12.445/26.791/61.365/20.049 ms";
61    /// let round_trip_statistics = RoundTripStatistics::from_str(&str),unwrap();
62    /// assert_eq!(round_trip_statistics.min, 12.445);
63    /// assert_eq!(round_trip_statistics.max, 61.365);
64    /// assert_eq!(round_trip_statistics.average, 26.791);
65    /// assert_eq!(round_trip_statistics.standard_deviation, 20.049);
66    /// ```
67    ///
68    fn from_str(s: &str) -> Result<Self, Self::Err> {
69        let r = regex::Regex::new(r"(?ms)^round-trip min/avg/max/stddev = (?<min>[\d\.]+)/(?<average>[\d\.]+)/(?<max>[\d\.]+)/(?<standard_deviation>[\d\.]+) ms").unwrap();
70        if let Some(captures) = r.captures(s) {
71            let min = captures["min"].parse::<f64>().unwrap_or(f64::NAN);
72            let max: f64 = captures["max"].parse::<f64>().unwrap_or(f64::NAN);
73            let average = captures["average"].parse::<f64>().unwrap_or(f64::NAN);
74            let standard_deviation = captures["standard_deviation"].parse::<f64>().unwrap_or(f64::NAN);
75            return Ok(
76                Self {
77                    min, 
78                    max, 
79                    average, 
80                    standard_deviation,
81                }
82            )
83        }
84        return Err(ParseError)
85    }
86}
87
88#[cfg(test)]
89mod tests {
90   use super::*;
91
92   mod display {
93       use super::*;
94
95        #[test]
96        fn test_display() {
97            let x = RoundTripStatistics {
98                min: 12.445,
99                max: 61.365,
100                average: 26.791,
101                standard_deviation: 20.049,
102            };
103            let actual = x.to_string();
104            let expect = concat!(
105                "min: 12.445\n",
106                "max: 61.365\n",
107                "average: 26.791\n",
108                "standard deviation: 20.049",
109            );
110            assert_eq!(actual, expect);
111        }
112
113    }
114
115    mod from_str {
116       use super::*;
117       use std::str::FromStr;
118
119        #[test]
120        fn test_present() {
121            let str = "round-trip min/avg/max/stddev = 12.445/26.791/61.365/20.049 ms";
122            let result = RoundTripStatistics::from_str(&str);
123            assert!(result.is_ok());
124            let x = result.unwrap();
125            assert_eq!(x.min, 12.445);
126            assert_eq!(x.max, 61.365);
127            assert_eq!(x.average, 26.791);
128            assert_eq!(x.standard_deviation, 20.049);
129        }
130
131        #[test]
132        fn test_absent() {
133            let str = "hello world";
134            let result = RoundTripStatistics::from_str(&str);
135            assert!(result.is_err());
136        }
137
138    }
139
140}
141