ogn_parser/
timestamp.rs

1use std::fmt::{Display, Formatter};
2use std::str::FromStr;
3
4use crate::AprsError;
5use serde::Serialize;
6
7#[derive(Eq, PartialEq, Debug, Clone)]
8pub enum Timestamp {
9    /// Day of month, Hour and Minute in UTC
10    DDHHMM(u8, u8, u8),
11    /// Hour, Minute and Second in UTC
12    HHMMSS(u8, u8, u8),
13    /// Unsupported timestamp format
14    Unsupported(String),
15}
16
17impl FromStr for Timestamp {
18    type Err = AprsError;
19
20    fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
21        let b = s.as_bytes();
22
23        if b.len() != 7 {
24            return Err(AprsError::InvalidTimestamp(s.to_owned()));
25        }
26
27        let one = s[0..2]
28            .parse::<u8>()
29            .map_err(|_| AprsError::InvalidTimestamp(s.to_owned()))?;
30        let two = s[2..4]
31            .parse::<u8>()
32            .map_err(|_| AprsError::InvalidTimestamp(s.to_owned()))?;
33        let three = s[4..6]
34            .parse::<u8>()
35            .map_err(|_| AprsError::InvalidTimestamp(s.to_owned()))?;
36
37        Ok(match b[6] as char {
38            'z' => Timestamp::DDHHMM(one, two, three),
39            'h' => Timestamp::HHMMSS(one, two, three),
40            '/' => Timestamp::Unsupported(s.to_owned()),
41            _ => return Err(AprsError::InvalidTimestamp(s.to_owned())),
42        })
43    }
44}
45
46impl Display for Timestamp {
47    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
48        match self {
49            Self::DDHHMM(d, h, m) => write!(f, "{:02}{:02}{:02}z", d, h, m),
50            Self::HHMMSS(h, m, s) => write!(f, "{:02}{:02}{:02}h", h, m, s),
51            Self::Unsupported(s) => write!(f, "{}", s),
52        }
53    }
54}
55
56impl Serialize for Timestamp {
57    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58    where
59        S: serde::Serializer,
60    {
61        serializer.serialize_str(&format!("{}", self))
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use csv::WriterBuilder;
68    use std::io::stdout;
69
70    use super::*;
71
72    #[test]
73    fn parse_ddhhmm() {
74        assert_eq!("123456z".parse(), Ok(Timestamp::DDHHMM(12, 34, 56)));
75    }
76
77    #[test]
78    fn parse_hhmmss() {
79        assert_eq!("123456h".parse(), Ok(Timestamp::HHMMSS(12, 34, 56)));
80    }
81
82    #[test]
83    fn parse_local_time() {
84        assert_eq!(
85            "123456/".parse::<Timestamp>(),
86            Ok(Timestamp::Unsupported("123456/".to_owned()))
87        );
88    }
89
90    #[test]
91    fn invalid_timestamp() {
92        assert_eq!(
93            "1234567".parse::<Timestamp>(),
94            Err(AprsError::InvalidTimestamp("1234567".to_owned()))
95        );
96    }
97
98    #[test]
99    fn invalid_timestamp2() {
100        assert_eq!(
101            "123a56z".parse::<Timestamp>(),
102            Err(AprsError::InvalidTimestamp("123a56z".to_owned()))
103        );
104    }
105
106    #[test]
107    fn test_serialize() {
108        let timestamp: Timestamp = "123456z".parse().unwrap();
109        let mut wtr = WriterBuilder::new().from_writer(stdout());
110        wtr.serialize(timestamp).unwrap();
111        wtr.flush().unwrap();
112    }
113}