nreplops_tool/conn_expr/
port_set.rs1use std::str;
17
18use super::parser::{self, Parser};
19
20pub type Port = u16;
21
22#[derive(Clone, Debug, PartialEq)]
24pub struct PortSet(Vec<Port>);
25
26impl PortSet {
27 pub fn try_from_iter(iter: impl Iterator<Item = Port>) -> Option<PortSet> {
28 let mut ports = vec![];
29 for port in iter {
30 if !ports.contains(&port) {
31 ports.push(port)
32 }
33 }
34 if ports.is_empty() {
35 None
36 } else {
37 Some(Self(ports))
38 }
39 }
40
41 pub fn as_slice(&self) -> &[Port] {
42 self.0.as_slice()
43 }
44
45 pub fn into_inner(self) -> Vec<Port> {
46 self.0
47 }
48}
49
50impl<'a> TryFrom<parser::Pair<'a, parser::Rule>> for PortSet {
51 type Error = CannotConvertToPortSetError;
52
53 fn try_from(
54 pair: parser::Pair<'a, parser::Rule>,
55 ) -> Result<Self, Self::Error> {
56 use parser::Rule;
57 if matches!(pair.as_rule(), Rule::port_set) {
58 let mut ports = vec![];
59 for p in pair.into_inner() {
60 match p.as_rule() {
61 Rule::port => ports.push(
62 p.as_str()
63 .parse()
64 .map_err(|_| CannotConvertToPortSetError)?,
65 ),
66 Rule::port_range => {
67 let mut limits = p.into_inner();
68 let start: Port = limits
69 .next()
70 .expect("grammar guarantees start port")
71 .as_str()
72 .parse()
73 .map_err(|_| CannotConvertToPortSetError)?;
74 let end = limits
75 .next()
76 .expect("grammar guarantees end port")
77 .as_str()
78 .parse()
79 .map_err(|_| CannotConvertToPortSetError)?;
80 if start <= end {
81 ports.extend(start..=end);
82 } else {
83 ports.extend((end..=start).rev());
84 }
85 }
86 _ => unreachable!("grammar guarantees port or port_range"),
87 }
88 }
89 Ok(
90 Self::try_from_iter(ports.into_iter())
91 .expect("grammar guarantees at least one port"),
92 )
93 } else {
94 Err(CannotConvertToPortSetError)
95 }
96 }
97}
98
99#[derive(Debug, PartialEq, thiserror::Error)]
100#[error("cannot convert to port set")]
101pub struct CannotConvertToPortSetError;
102
103impl str::FromStr for PortSet {
104 type Err = PortSetParseError;
105
106 fn from_str(s: &str) -> Result<Self, Self::Err> {
107 parser::ConnectionExprLanguage::parse(parser::Rule::port_set_expr, s)
108 .map_err(|_| PortSetParseError)?
109 .next()
110 .expect("grammar guaranteed post_set_expr")
111 .into_inner()
112 .next()
113 .expect("grammar guarantees post_set")
114 .try_into()
115 .map_err(|_| PortSetParseError)
116 }
117}
118
119#[derive(Debug, PartialEq, thiserror::Error)]
120#[error("cannot parse port set expression")]
121pub struct PortSetParseError;
122
123#[cfg(test)]
124mod test {
125 use super::*;
126
127 #[test]
128 fn port_set_parsing() {
129 assert_eq!("1".parse(), Ok(PortSet(vec![1])));
130 assert_eq!("65535".parse(), Ok(PortSet(vec![65535])));
131 assert_eq!("1,2".parse(), Ok(PortSet(vec![1, 2])));
132 assert_eq!("1-3".parse(), Ok(PortSet(vec![1, 2, 3])));
133 assert_eq!("3-1".parse(), Ok(PortSet(vec![3, 2, 1])));
134 assert_eq!("1,1-2,5,2-4".parse(), Ok(PortSet(vec![1, 2, 5, 3, 4])));
135 assert_eq!("".parse::<PortSet>(), Err(PortSetParseError));
136 assert_eq!(" 1".parse::<PortSet>(), Err(PortSetParseError));
137 assert_eq!("1 ".parse::<PortSet>(), Err(PortSetParseError));
138 assert_eq!(",".parse::<PortSet>(), Err(PortSetParseError));
139 assert_eq!(",1".parse::<PortSet>(), Err(PortSetParseError));
140 assert_eq!("1,".parse::<PortSet>(), Err(PortSetParseError));
141 assert_eq!("-1".parse::<PortSet>(), Err(PortSetParseError));
142 assert_eq!("1-".parse::<PortSet>(), Err(PortSetParseError));
143 assert_eq!("1,,2".parse::<PortSet>(), Err(PortSetParseError));
144 assert_eq!("1--2".parse::<PortSet>(), Err(PortSetParseError));
145 assert_eq!("1-2-3".parse::<PortSet>(), Err(PortSetParseError));
146 assert_eq!("65536".parse::<PortSet>(), Err(PortSetParseError));
147 }
148}