Implement FromStr for IpEndpoint

Fixes #81
This commit is contained in:
Herman J. Radtke III 2017-12-23 09:09:35 -08:00 committed by whitequark
parent fe3e67d544
commit 260e3d996f
1 changed files with 81 additions and 1 deletions

View File

@ -3,7 +3,7 @@
use core::str::FromStr;
use core::result;
use wire::{EthernetAddress, IpAddress, IpCidr};
use wire::{EthernetAddress, IpAddress, IpCidr, IpEndpoint};
use wire::{Ipv4Address, Ipv4Cidr};
#[cfg(feature = "proto-ipv6")]
use wire::{Ipv6Address, Ipv6Cidr};
@ -260,6 +260,49 @@ impl<'a> Parser<'a> {
Err(())
}
fn accept_ipv4_endpoint(&mut self) -> Result<IpEndpoint> {
let ip = self.accept_ipv4()?;
let port = if self.accept_eof().is_ok() {
0
} else {
self.accept_char(b':')?;
self.accept_number(5, 65535, false)?
};
Ok(IpEndpoint { addr: IpAddress::Ipv4(ip), port: port as u16 })
}
#[cfg(feature = "proto-ipv6")]
fn accept_ipv6_endpoint(&mut self, is_cidr: bool) -> Result<IpEndpoint> {
if self.lookahead_char(b'[') {
self.accept_char(b'[')?;
let ip = self.accept_ipv6(false)?;
self.accept_char(b']')?;
self.accept_char(b':')?;
let port = self.accept_number(5, 65535, false)?;
Ok(IpEndpoint { addr: IpAddress::Ipv6(ip), port: port as u16 })
} else {
let ip = self.accept_ipv6(is_cidr)?;
Ok(IpEndpoint { addr: IpAddress::Ipv6(ip), port: 0 })
}
}
fn accept_ip_endpoint(&mut self) -> Result<IpEndpoint> {
if let Some(ipv4) = self.try(|p| p.accept_ipv4_endpoint()) {
return Ok(ipv4)
}
#[cfg(feature = "proto-ipv6")]
match self.try(|p| p.accept_ipv6_endpoint(false)) {
Some(ipv6) => return Ok(ipv6),
None => ()
}
Err(())
}
}
impl FromStr for EthernetAddress {
@ -348,6 +391,14 @@ impl FromStr for IpCidr {
}
}
impl FromStr for IpEndpoint {
type Err = ();
fn from_str(s: &str) -> Result<IpEndpoint> {
Parser::new(s).until_eof(|p| Ok(p.accept_ip_endpoint()?))
}
}
#[cfg(test)]
mod test {
use super::*;
@ -511,4 +562,33 @@ mod test {
];
check_cidr_test_array!(tests, Ipv6Cidr::from_str, IpCidr::Ipv6);
}
#[test]
fn test_endpoint_ipv4() {
assert_eq!(IpEndpoint::from_str(""), Err(()));
assert_eq!(IpEndpoint::from_str("x"), Err(()));
assert_eq!(
IpEndpoint::from_str("127.0.0.1"),
Ok(IpEndpoint { addr: IpAddress::v4(127, 0, 0, 1), port: 0 })
);
assert_eq!(
IpEndpoint::from_str("127.0.0.1:12345"),
Ok(IpEndpoint { addr: IpAddress::v4(127, 0, 0, 1), port: 12345 })
);
}
#[test]
#[cfg(feature = "proto-ipv6")]
fn test_endpoint_ipv6() {
assert_eq!(IpEndpoint::from_str(""), Err(()));
assert_eq!(IpEndpoint::from_str("x"), Err(()));
assert_eq!(
IpEndpoint::from_str("fe80::1"),
Ok(IpEndpoint { addr: IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), port: 0 })
);
assert_eq!(
IpEndpoint::from_str("[fe80::1]:12345"),
Ok(IpEndpoint { addr: IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), port: 12345 })
);
}
}