ogn_parser/
message.rs

1use std::fmt::{Display, Formatter};
2
3use serde::Serialize;
4
5use crate::AprsError;
6use crate::FromStr;
7
8#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
9pub struct AprsMessage {
10    pub addressee: String,
11    pub text: String,
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub id: Option<u32>,
14}
15
16impl FromStr for AprsMessage {
17    type Err = AprsError;
18
19    fn from_str(s: &str) -> Result<Self, AprsError> {
20        let mut splitter = s.splitn(2, ':');
21
22        let addressee = match splitter.next() {
23            Some(x) => x,
24            None => {
25                return Err(AprsError::InvalidMessageDestination("".to_string()));
26            }
27        };
28
29        if addressee.len() != 9 {
30            return Err(AprsError::InvalidMessageDestination(addressee.to_string()));
31        }
32
33        let addressee = addressee.trim().to_string();
34
35        let text = splitter.next().unwrap_or("");
36        let mut text_splitter = text.splitn(2, '{');
37        let text = text_splitter.next().unwrap_or("").to_string();
38        let id_s = text_splitter.next();
39
40        let id: Option<u32> = match id_s {
41            Some(s) => {
42                let id = s.parse();
43
44                match id {
45                    Ok(x) => {
46                        if x < 100_000 {
47                            Some(x)
48                        } else {
49                            return Err(AprsError::InvalidMessageId(s.to_string()));
50                        }
51                    }
52
53                    Err(_) => return Err(AprsError::InvalidMessageId(s.to_string())),
54                }
55            }
56            None => None,
57        };
58
59        Ok(Self {
60            addressee,
61            text,
62            id,
63        })
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn parse_message_invalid_dest() {
73        // Dest must be padded with spaces to 9 characters long
74        let result = r"DEST  :Hello World! This msg has a : colon {32975".parse::<AprsMessage>();
75
76        assert_eq!(
77            result,
78            Err(AprsError::InvalidMessageDestination("DEST  ".to_string()))
79        );
80    }
81
82    #[test]
83    fn parse_message_invalid_id() {
84        let result =
85            r"DESTINATI:Hello World! This msg has a : colon {329754".parse::<AprsMessage>();
86
87        assert_eq!(
88            result,
89            Err(AprsError::InvalidMessageId("329754".to_string()))
90        );
91    }
92}
93
94impl Display for AprsMessage {
95    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
96        write!(f, ":{: <9}:{}", self.addressee, self.text)?;
97
98        if let Some(id) = self.id {
99            write!(f, "{{{id}")?;
100        }
101
102        Ok(())
103    }
104}