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