1use std::num::ParseIntError;
6
7use mt_raw::MtRaw;
8use mt_structured::MtStructured;
9use rss::Rss;
10use thiserror::Error;
11
12pub mod mt_raw;
13pub mod mt_structured;
14pub mod rss;
15
16#[derive(Error, Clone, Debug, PartialEq)]
18pub enum ParseError {
19 #[error("failed to parse number")]
20 ParseIntError(#[from] ParseIntError),
21
22 #[error("invalid message size (expected {expected:?}, found {found:?})")]
23 SizeNotMatch { expected: usize, found: usize },
24
25 #[error("invalid sentence, not parsable")]
26 Invalid,
27}
28
29#[derive(Clone, Debug, PartialEq)]
31pub enum ParsedMessage {
32 Rss(Rss),
34
35 MtStructured(MtStructured),
37
38 MtRaw(MtRaw),
40
41 Invalid,
43}
44
45pub fn parse(message: &str) -> Result<ParsedMessage, ParseError> {
62 let parsed = match message.trim() {
63 msg if rss::is_rss(msg) => ParsedMessage::Rss(rss::parse(msg)?),
64 msg if mt_structured::is_mt(msg) => ParsedMessage::MtStructured(mt_structured::parse(msg)?),
65 msg if mt_raw::is_mt(msg) => ParsedMessage::MtRaw(mt_raw::parse(msg)?),
66 _ => ParsedMessage::Invalid,
67 };
68 Ok(parsed)
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn sample_usage() {
77 let samples = vec![
78 "MT1001000AL400C592753572B323433212S1723756E4706",
79 "MT6001001FFFE2FA00E0000CBAB959DB0903788C71B79F84B",
80 "SS,A,123",
81 "SS,1,123",
82 ];
83
84 for s in samples {
85 println!("{:?}", parse(s));
86 }
87 }
88
89 #[test]
90 fn mt_structured() {
91 assert!(parse("MT1001000AL400C592753572B323433212S1723756E4706").is_ok());
92 assert!(parse("MT1001000AL400C592753572B323433212S1723756E4706").is_ok());
93 }
94
95 #[test]
96 fn mt_raw() {
97 assert!(parse("MT6001001FFFE2FA00E0000CBAB959DB0903788C71B79F84B").is_ok());
98 assert!(parse("MT6001001FFFE2FA0062C93A9AB959E55EE7788C71B791131").is_ok());
99 }
100
101 #[test]
102 fn invalid_mt() {
103 let invalid_samples = vec![
105 "MT2001000AL400C592753572B323433212S1723756E4706",
106 "MT3001000AL400C592753572B323433212S1723756E4706",
107 "MT4001000AL400C592753572B323433212S1723756E4706",
108 "MT5001000AL400C592753572B323433212S1723756E4706",
109 "MT8001000AL400C592753572B323433212S1723756E4706",
110 "MT9001000AL400C592753572B323433212S1723756E4706",
111 "MT0001000AL400C592753572B323433212S1723756E4706",
112 ];
113 for s in invalid_samples {
114 assert_eq!(parse(s).unwrap(), ParsedMessage::Invalid);
115 }
116
117 assert!(parse("MT6001001FFFE2FA00E0000CBAB959DB0903788C71B").is_err());
119 assert!(parse("MT1001000AL400C592753572B323433212S172375").is_err());
120
121 assert!(parse("MT1001aaaAL400C592753572B323433212S1723756E4706").is_err());
128 assert!(parse("MT6001aaaFFFE2FA00E0000CBAB959DB0903788C71B79F84B").is_err());
129
130 assert!(parse("MT6001001FFFE2FA00E0000CBAB959DB0903788C71B79ZZZZ").is_err());
132 }
133
134 #[test]
135 fn rss() {
136 assert!(parse("SS,A,123\n").is_ok());
137 assert!(parse("SS,1,123\n").is_ok());
138 }
139
140 #[test]
141 fn invalid_rss() {
142 assert!(parse("SS,1,666\n").is_err()); assert!(parse("SS,1,12367\n").is_err()); assert!(parse("SS,2,123\n").is_err()); assert!(parse("SS,A,1234\n").is_err()); assert!(parse("SS,X,123\n").is_err()); }
148
149 #[test]
150 fn hardcoded_checksum() {
151 assert_eq!(
152 mt_raw::compute_checksum("FFFE2FA00E0000CBAB959DB0903788C71B79".as_bytes()),
153 0xf84b
154 );
155 }
156
157 #[test]
158 fn mt_raw_checksum() {
159 if let Ok(ParsedMessage::MtRaw(v)) =
160 parse("MT6001001FFFE2FA00E0000CBAB959DB0903788C71B79F84B")
161 {
162 assert_eq!(mt_raw::compute_checksum(&v.data.as_bytes()), v.checksum);
163 }
164 }
165}