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
use std::{convert::TryFrom, error};
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum FilterClass<'a> {
AsSet(&'a str),
RouteSet(&'a str),
AutNum(u32),
}
impl<'a> TryFrom<&'a str> for FilterClass<'a> {
type Error = Box<dyn error::Error>;
fn try_from(input: &'a str) -> Result<FilterClass<'a>, Self::Error> {
if input.contains(':') {
let elems = input.split(':');
for elem in elems {
match parse_name_component(elem) {
Ok(FilterClass::AutNum(_)) | Err(_) => continue,
Ok(FilterClass::AsSet(_)) => return Ok(FilterClass::AsSet(input)),
Ok(FilterClass::RouteSet(_)) => return Ok(FilterClass::RouteSet(input)),
}
}
Err(input.into())
} else {
parse_name_component(input)
}
}
}
fn parse_name_component(input: &str) -> Result<FilterClass, Box<dyn error::Error>> {
match input.get(0..3) {
Some(name) if name.eq_ignore_ascii_case("as-") => Ok(FilterClass::AsSet(input)),
Some(name) if name.eq_ignore_ascii_case("rs-") => Ok(FilterClass::RouteSet(input)),
Some(name) if name[..2].eq_ignore_ascii_case("as") => input[2..]
.parse::<u32>()
.map(FilterClass::AutNum)
.map_err(|_| input.into()),
_ => Err(input.into()),
}
}
#[cfg(test)]
mod tests {
use crate::*;
mod realworld {
use super::*;
use filterclass::*;
use std::{
fs::File,
io::{prelude::*, BufReader},
};
#[test]
#[ignore]
fn parse_route_set_names() {
let mut num_parsed = 0;
File::open("ripe.db.route-set")
.map(BufReader::new)
.unwrap()
.lines()
.filter_map(Result::ok)
.filter(|l| l.starts_with("route-set:"))
.for_each(|line| {
let name = line.split_whitespace().nth(1).unwrap();
match FilterClass::try_from(name).unwrap() {
FilterClass::RouteSet(_) => num_parsed += 1,
_ => panic!(name.to_owned()),
}
});
eprintln!("All {} route-set names parsed correctly", num_parsed);
}
#[test]
#[ignore]
fn parse_as_set_names() {
let mut num_parsed = 0;
File::open("ripe.db.as-set")
.map(BufReader::new)
.unwrap()
.lines()
.filter_map(Result::ok)
.filter(|l| l.starts_with("as-set:"))
.for_each(|line| {
let name = line.split_whitespace().nth(1).unwrap();
match FilterClass::try_from(name).unwrap() {
FilterClass::AsSet(_) => num_parsed += 1,
_ => panic!(name.to_owned()),
}
});
eprintln!("All {} as-set names parsed correctly", num_parsed);
}
}
}