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 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}