cidr/
local_addr_parser.rs

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
use core::str::FromStr;
use std::net::{
	AddrParseError,
	IpAddr,
	Ipv4Addr,
	Ipv6Addr,
};

pub trait ParseableAddress: Sized {
	fn address_from_str(s: &str) -> Result<Self, AddrParseError>;
}

fn special_ipv4_parser(s: &str) -> Option<Ipv4Addr> {
	Some(
		crate::parsers::parse_short_ipv4_address_as_cidr(s)
			.ok()?
			.first_address(),
	)
}

impl ParseableAddress for Ipv4Addr {
	fn address_from_str(s: &str) -> Result<Self, AddrParseError> {
		match FromStr::from_str(s) {
			Ok(addr) => Ok(addr),
			Err(err) => match special_ipv4_parser(s) {
				Some(addr) => Ok(addr),
				None => Err(err),
			},
		}
	}
}

impl ParseableAddress for Ipv6Addr {
	fn address_from_str(s: &str) -> Result<Self, AddrParseError> {
		FromStr::from_str(s)
	}
}

impl ParseableAddress for IpAddr {
	fn address_from_str(s: &str) -> Result<Self, AddrParseError> {
		match FromStr::from_str(s) {
			Ok(addr) => Ok(addr),
			Err(err) => match special_ipv4_parser(s) {
				Some(addr) => Ok(Self::V4(addr)),
				None => Err(err),
			},
		}
	}
}

#[cfg(test)]
mod tests {
	use super::ParseableAddress;
	use std::net::{
		IpAddr,
		Ipv4Addr,
	};

	fn test_addr(s: &str, a: Ipv4Addr) {
		assert_eq!(
			Ipv4Addr::address_from_str(s).unwrap(),
			a,
			"{} didn't match {:?} (through Ipv4Addr)",
			s,
			a
		);

		assert_eq!(
			IpAddr::address_from_str(s).unwrap(),
			IpAddr::V4(a),
			"{} didn't match {:?} (through IpAddr)",
			s,
			a
		);
	}

	#[test]
	fn invalid_short() {
		assert!(IpAddr::address_from_str("").is_err());
		assert!(Ipv4Addr::address_from_str("").is_err());
	}

	#[test]
	fn short_10() {
		test_addr("10", Ipv4Addr::new(10, 0, 0, 0));
		test_addr("10.0", Ipv4Addr::new(10, 0, 0, 0));
		test_addr("10.0.0", Ipv4Addr::new(10, 0, 0, 0));
		test_addr("10.0.0.0", Ipv4Addr::new(10, 0, 0, 0));
	}

	#[test]
	fn short_192_168() {
		test_addr("192.168", Ipv4Addr::new(192, 168, 0, 0));
		test_addr("192.168.0", Ipv4Addr::new(192, 168, 0, 0));
		test_addr("192.168.0.0", Ipv4Addr::new(192, 168, 0, 0));
	}

	#[test]
	fn short_192_0_2() {
		test_addr("192.0.2", Ipv4Addr::new(192, 0, 2, 0));
		test_addr("192.0.2.0", Ipv4Addr::new(192, 0, 2, 0));
	}
}