nreplops_tool/conn_expr/
port_set.rs

1// conn_expr/port_set.rs
2// Copyright 2022 Matti Hänninen
3//
4// Licensed under the Apache License, Version 2.0 (the "License"); you may not
5// use this file except in compliance with the License. You may obtain a copy of
6// the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13// License for the specific language governing permissions and limitations under
14// the License.
15
16use std::str;
17
18use super::parser::{self, Parser};
19
20pub type Port = u16;
21
22/// Non-empty ordered set of ports
23#[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}