From c4348952671610ed29777cff26d0f0196fb50de5 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Thu, 18 Oct 2018 13:35:51 -0700 Subject: [PATCH] change Port<'a> to be Port Closes #263 --- src/uri/authority.rs | 4 +- src/uri/mod.rs | 6 ++- src/uri/port.rs | 102 ++++++++++++++++++++++++++++++++----------- 3 files changed, 83 insertions(+), 29 deletions(-) diff --git a/src/uri/authority.rs b/src/uri/authority.rs index f8a92d82..0e94b717 100644 --- a/src/uri/authority.rs +++ b/src/uri/authority.rs @@ -181,7 +181,7 @@ impl Authority { host(self.as_str()) } - #[deprecated(since="0.2.0", note="please use `port_part` instead")] + #[deprecated(since="0.1.14", note="use `port_part` instead")] #[doc(hidden)] pub fn port(&self) -> Option { self.port_part().and_then(|p| Some(p.as_u16())) @@ -221,7 +221,7 @@ impl Authority { /// /// assert!(authority.port_part().is_none()); /// ``` - pub fn port_part(&self) -> Option { + pub fn port_part(&self) -> Option> { let bytes = self.as_str(); bytes .rfind(":") diff --git a/src/uri/mod.rs b/src/uri/mod.rs index dbd3b541..65d56e23 100644 --- a/src/uri/mod.rs +++ b/src/uri/mod.rs @@ -137,6 +137,7 @@ enum ErrorKind { InvalidUriChar, InvalidScheme, InvalidAuthority, + InvalidPort, InvalidFormat, SchemeMissing, AuthorityMissing, @@ -568,7 +569,7 @@ impl Uri { self.authority_part().map(|a| a.host()) } - #[deprecated(since="0.2.0", note="please use `port_part` instead")] + #[deprecated(since="0.1.14", note="use `port_part` instead")] #[doc(hidden)] pub fn port(&self) -> Option { self.port_part().and_then(|p| Some(p.as_u16())) @@ -617,7 +618,7 @@ impl Uri { /// /// assert!(uri.port_part().is_none()); /// ``` - pub fn port_part(&self) -> Option { + pub fn port_part(&self) -> Option> { self.authority_part() .and_then(|a| a.port_part()) } @@ -1045,6 +1046,7 @@ impl Error for InvalidUri { ErrorKind::InvalidUriChar => "invalid uri character", ErrorKind::InvalidScheme => "invalid scheme", ErrorKind::InvalidAuthority => "invalid authority", + ErrorKind::InvalidPort => "invalid port", ErrorKind::InvalidFormat => "invalid format", ErrorKind::SchemeMissing => "scheme missing", ErrorKind::AuthorityMissing => "authority missing", diff --git a/src/uri/port.rs b/src/uri/port.rs index 88ddb0b0..d3177a7a 100644 --- a/src/uri/port.rs +++ b/src/uri/port.rs @@ -1,21 +1,14 @@ -use std::{fmt, num}; -use std::str::FromStr; +use std::fmt; + +use super::{ErrorKind, InvalidUri}; /// The port component of a URI. -#[derive(Debug)] -pub struct Port<'a> { - bytes: &'a str, +pub struct Port { port: u16, + repr: T, } -impl<'a> Port<'a> { - /// Converts a `str` to a port number. - /// - /// The supplied `str` must be a valid u16. - pub(crate) fn from_str(bytes: &'a str) -> Result { - u16::from_str(bytes).and_then(|port| Ok(Port { port, bytes })) - } - +impl Port { /// Returns the port number as a `u16`. /// /// # Examples @@ -32,6 +25,27 @@ impl<'a> Port<'a> { pub fn as_u16(&self) -> u16 { self.port } +} + +impl Port +where + T: AsRef, +{ + /// Converts a `str` to a port number. + /// + /// The supplied `str` must be a valid u16. + pub(crate) fn from_str(bytes: T) -> Result { + bytes + .as_ref() + .parse::() + .map(|port| Port { + port, + repr: bytes, + }) + .map_err(|_| { + ErrorKind::InvalidPort.into() + }) + } /// Returns the port number as a `str`. /// @@ -46,41 +60,63 @@ impl<'a> Port<'a> { /// let port = authority.port_part().unwrap(); /// assert_eq!(port.as_str(), "80"); /// ``` - pub fn as_str(&self) -> &'a str { - self.bytes + pub fn as_str(&self) -> &str { + self.repr.as_ref() + } +} + +impl fmt::Debug for Port +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Port") + .field(&self.port) + .finish() } } -impl<'a> fmt::Display for Port<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}", self.bytes) +impl fmt::Display for Port { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Use `u16::fmt` so that it respects any formatting flags that + // may have been set (like padding, align, etc). + fmt::Display::fmt(&self.port, f) } } -impl<'a> From> for u16 { - fn from(port: Port) -> Self { +impl From> for u16 { + fn from(port: Port) -> Self { port.as_u16() } } -impl<'a> AsRef for Port<'a> { +impl AsRef for Port +where + T: AsRef, +{ fn as_ref(&self) -> &str { self.as_str() } } -impl<'a> PartialEq for Port<'a> { - fn eq(&self, other: &Self) -> bool { +impl PartialEq> for Port { + fn eq(&self, other: &Port) -> bool { self.port == other.port } } -impl<'a> PartialEq for Port<'a> { +impl PartialEq for Port { fn eq(&self, other: &u16) -> bool { self.port == *other } } +impl PartialEq> for u16 { + fn eq(&self, other: &Port) -> bool { + other.port == *self + } +} + #[cfg(test)] mod tests { use super::*; @@ -92,10 +128,26 @@ mod tests { assert_eq!(port_a, port_b); } + #[test] + fn partialeq_port_different_reprs() { + let port_a = Port { + repr: "8081", + port: 8081, + }; + let port_b = Port { + repr: String::from("8081"), + port: 8081, + }; + assert_eq!(port_a, port_b); + assert_eq!(port_b, port_a); + } + #[test] fn partialeq_u16() { let port = Port::from_str("8080").unwrap(); - assert_eq!(port, 8080u16); + // test equals in both directions + assert_eq!(port, 8080); + assert_eq!(8080, port); } #[test]