1use std::fmt;
2
3use crate::util::ParseError;
4
5#[derive(Debug, PartialEq, Eq)]
6pub enum GpsQualifier {
7 Gps,
8 DGps,
9}
10
11#[derive(Debug, PartialEq, Eq)]
13pub struct DRecord<'a> {
14 pub qualifier: GpsQualifier,
15 pub station_id: &'a str,
16}
17
18impl<'a> DRecord<'a> {
19 pub fn parse(line: &'a str) -> Result<Self, ParseError> {
20 if line.len() != 6 {
21 return Err(ParseError::SyntaxError);
22 }
23
24 let bytes = line.as_bytes();
25 assert_eq!(bytes[0], b'D');
26
27 let qualifier = match bytes[1] {
28 b'1' => GpsQualifier::Gps,
29 b'2' => GpsQualifier::DGps,
30 _ => return Err(ParseError::SyntaxError),
31 };
32
33 let station_id = &line[2..6];
34
35 Ok(DRecord {
36 qualifier,
37 station_id,
38 })
39 }
40}
41
42impl<'a> fmt::Display for DRecord<'a> {
43 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44 let qual_str = match self.qualifier {
45 GpsQualifier::Gps => '1',
46 GpsQualifier::DGps => '2',
47 };
48
49 write!(f, "D{}{}", qual_str, self.station_id)
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::{DRecord, GpsQualifier};
56
57 #[test]
58 fn drecord_parse() {
59 let example_line = "D1ABCD";
60 let parsed = DRecord::parse(example_line).unwrap();
61 let expected = DRecord {
62 qualifier: GpsQualifier::Gps,
63 station_id: "ABCD",
64 };
65
66 assert_eq!(parsed, expected);
67 }
68
69 #[test]
70 fn drecord_format() {
71 let expected_string = "D1ABCD";
72 let record = DRecord {
73 qualifier: GpsQualifier::Gps,
74 station_id: "ABCD",
75 };
76
77 assert_eq!(format!("{}", record), expected_string);
78 }
79
80 proptest! {
81 #[test]
82 #[allow(unused_must_use)]
83 fn parse_doesnt_crash(s in "D\\PC*") {
84 DRecord::parse(&s);
85 }
86 }
87}