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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use std::convert::TryFrom;
use std::fmt::{Display, Formatter};
use AprsError;
#[derive(Eq, PartialEq, Debug, Clone)]
pub struct Callsign {
pub call: String,
pub ssid: Option<String>,
}
impl Callsign {
pub fn new<T: Into<String>>(call: T, ssid: Option<T>) -> Callsign {
Callsign {
call: call.into(),
ssid: ssid.map(|ssid| ssid.into()),
}
}
}
impl TryFrom<&[u8]> for Callsign {
type Error = AprsError;
fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
let s = std::str::from_utf8(b).map_err(|_| AprsError::NonUtf8Callsign(b.to_owned()))?;
match s.split_once('-') {
Some((call, ssid)) => {
if call.is_empty() {
Err(AprsError::EmptyCallsign(s.to_owned()))
} else if ssid.is_empty() {
Err(AprsError::EmptySSID(s.to_owned()))
} else {
Ok(Callsign::new(call, Some(ssid)))
}
}
None => Ok(Callsign::new(s, None)),
}
}
}
impl Display for Callsign {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "{}", self.call)?;
if let Some(ssid) = &self.ssid {
write!(f, "-{}", ssid)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::convert::TryInto;
#[test]
fn parse_callsign() {
assert_eq!(
"ABCDEF".as_bytes().try_into(),
Ok(Callsign::new("ABCDEF", None))
);
}
#[test]
fn parse_with_ssid() {
assert_eq!(
"ABCDEF-42".as_bytes().try_into(),
Ok(Callsign::new("ABCDEF", Some("42")))
);
}
#[test]
fn empty_callsign() {
assert_eq!(
Callsign::try_from("-42".as_bytes()),
Err(AprsError::EmptyCallsign("-42".to_owned()))
);
}
#[test]
fn empty_ssid() {
assert_eq!(
Callsign::try_from("ABCDEF-".as_bytes()),
Err(AprsError::EmptySSID("ABCDEF-".to_owned()))
);
}
#[test]
fn non_utf8() {
assert_eq!(
Callsign::try_from(&b"ABCDEF\xF0\xA4\xAD"[..]),
Err(AprsError::NonUtf8Callsign(b"ABCDEF\xF0\xA4\xAD".to_vec()))
);
}
#[test]
fn display_no_ssid() {
assert_eq!("ABCDEF", format!("{}", Callsign::new("ABCDEF", None)));
}
#[test]
fn display_with_ssid() {
assert_eq!(
"ABCDEF-12",
format!("{}", Callsign::new("ABCDEF", Some("12")))
);
}
}