cidr/
local_addr_parser.rs

1use core::str::FromStr;
2use std::net::{
3	AddrParseError,
4	IpAddr,
5	Ipv4Addr,
6	Ipv6Addr,
7};
8
9pub trait ParseableAddress: Sized {
10	fn address_from_str(s: &str) -> Result<Self, AddrParseError>;
11}
12
13fn special_ipv4_parser(s: &str) -> Option<Ipv4Addr> {
14	Some(
15		crate::parsers::parse_short_ipv4_address_as_cidr(s)
16			.ok()?
17			.first_address(),
18	)
19}
20
21impl ParseableAddress for Ipv4Addr {
22	fn address_from_str(s: &str) -> Result<Self, AddrParseError> {
23		match FromStr::from_str(s) {
24			Ok(addr) => Ok(addr),
25			Err(err) => match special_ipv4_parser(s) {
26				Some(addr) => Ok(addr),
27				None => Err(err),
28			},
29		}
30	}
31}
32
33impl ParseableAddress for Ipv6Addr {
34	fn address_from_str(s: &str) -> Result<Self, AddrParseError> {
35		FromStr::from_str(s)
36	}
37}
38
39impl ParseableAddress for IpAddr {
40	fn address_from_str(s: &str) -> Result<Self, AddrParseError> {
41		match FromStr::from_str(s) {
42			Ok(addr) => Ok(addr),
43			Err(err) => match special_ipv4_parser(s) {
44				Some(addr) => Ok(Self::V4(addr)),
45				None => Err(err),
46			},
47		}
48	}
49}
50
51#[cfg(test)]
52mod tests {
53	use super::ParseableAddress;
54	use std::net::{
55		IpAddr,
56		Ipv4Addr,
57	};
58
59	fn test_addr(s: &str, a: Ipv4Addr) {
60		assert_eq!(
61			Ipv4Addr::address_from_str(s).unwrap(),
62			a,
63			"{} didn't match {:?} (through Ipv4Addr)",
64			s,
65			a
66		);
67
68		assert_eq!(
69			IpAddr::address_from_str(s).unwrap(),
70			IpAddr::V4(a),
71			"{} didn't match {:?} (through IpAddr)",
72			s,
73			a
74		);
75	}
76
77	#[test]
78	fn invalid_short() {
79		assert!(IpAddr::address_from_str("").is_err());
80		assert!(Ipv4Addr::address_from_str("").is_err());
81	}
82
83	#[test]
84	fn short_10() {
85		test_addr("10", Ipv4Addr::new(10, 0, 0, 0));
86		test_addr("10.0", Ipv4Addr::new(10, 0, 0, 0));
87		test_addr("10.0.0", Ipv4Addr::new(10, 0, 0, 0));
88		test_addr("10.0.0.0", Ipv4Addr::new(10, 0, 0, 0));
89	}
90
91	#[test]
92	fn short_192_168() {
93		test_addr("192.168", Ipv4Addr::new(192, 168, 0, 0));
94		test_addr("192.168.0", Ipv4Addr::new(192, 168, 0, 0));
95		test_addr("192.168.0.0", Ipv4Addr::new(192, 168, 0, 0));
96	}
97
98	#[test]
99	fn short_192_0_2() {
100		test_addr("192.0.2", Ipv4Addr::new(192, 0, 2, 0));
101		test_addr("192.0.2.0", Ipv4Addr::new(192, 0, 2, 0));
102	}
103}