From d6d5d6f684f640e9e435212a300d47d632c61740 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Wed, 24 Jul 2019 05:37:10 +0530 Subject: [PATCH] introduce TryFrom --- src/uri/authority.rs | 48 +++++++++++++---- src/uri/mod.rs | 126 ++++++++++++++++++++++++++----------------- src/uri/scheme.rs | 51 +++++++++++++----- 3 files changed, 153 insertions(+), 72 deletions(-) diff --git a/src/uri/authority.rs b/src/uri/authority.rs index 59510ad5..2ff43cfb 100644 --- a/src/uri/authority.rs +++ b/src/uri/authority.rs @@ -1,6 +1,7 @@ // Deprecated in 1.26, needed until our minimum version is >=1.23. #[allow(unused, deprecated)] use std::ascii::AsciiExt; +use std::convert::TryFrom; use std::hash::{Hash, Hasher}; use std::str::FromStr; use std::{cmp, fmt, str}; @@ -26,8 +27,7 @@ impl Authority { /// Attempt to convert an `Authority` from `Bytes`. /// - /// This function will be replaced by a `TryFrom` implementation once the - /// trait lands in stable. + /// This function has been replaced by `TryFrom` implementation. /// /// # Examples /// @@ -46,15 +46,7 @@ impl Authority { /// # } /// ``` pub fn from_shared(s: Bytes) -> Result { - let authority_end = Authority::parse_non_empty(&s[..]).map_err(InvalidUriBytes)?; - - if authority_end != s.len() { - return Err(ErrorKind::InvalidUriChar.into()); - } - - Ok(Authority { - data: unsafe { ByteStr::from_utf8_unchecked(s) }, - }) + TryFrom::try_from(s) } /// Attempt to convert an `Authority` from a static string. @@ -269,6 +261,40 @@ impl Authority { } } +impl TryFrom for Authority { + type Error = InvalidUriBytes; + /// Attempt to convert an `Authority` from `Bytes`. + /// + /// # Examples + /// + /// ``` + /// # extern crate http; + /// # use http::uri::*; + /// extern crate bytes; + /// + /// use std::convert::TryFrom; + /// use bytes::Bytes; + /// + /// # pub fn main() { + /// let bytes = Bytes::from("example.com"); + /// let authority = Authority::try_from(bytes).unwrap(); + /// + /// assert_eq!(authority.host(), "example.com"); + /// # } + /// ``` + fn try_from(s: Bytes) -> Result { + let authority_end = Authority::parse_non_empty(&s[..]).map_err(InvalidUriBytes)?; + + if authority_end != s.len() { + return Err(ErrorKind::InvalidUriChar.into()); + } + + Ok(Authority { + data: unsafe { ByteStr::from_utf8_unchecked(s) }, + }) + } +} + impl AsRef for Authority { fn as_ref(&self) -> &str { self.as_str() diff --git a/src/uri/mod.rs b/src/uri/mod.rs index c4353a82..d4625fb0 100644 --- a/src/uri/mod.rs +++ b/src/uri/mod.rs @@ -24,6 +24,7 @@ use crate::byte_str::ByteStr; use crate::HttpTryFrom; +use std::convert::TryFrom; use bytes::Bytes; @@ -241,8 +242,7 @@ impl Uri { /// Attempt to convert a `Uri` from `Bytes` /// - /// This function will be replaced by a `TryFrom` implementation once the - /// trait lands in stable. + /// This function has been replaced by `TryFrom` implementation. /// /// # Examples /// @@ -262,53 +262,7 @@ impl Uri { /// # } /// ``` pub fn from_shared(s: Bytes) -> Result { - use self::ErrorKind::*; - - if s.len() > MAX_LEN { - return Err(TooLong.into()); - } - - match s.len() { - 0 => { - return Err(Empty.into()); - } - 1 => match s[0] { - b'/' => { - return Ok(Uri { - scheme: Scheme::empty(), - authority: Authority::empty(), - path_and_query: PathAndQuery::slash(), - }); - } - b'*' => { - return Ok(Uri { - scheme: Scheme::empty(), - authority: Authority::empty(), - path_and_query: PathAndQuery::star(), - }); - } - _ => { - let authority = Authority::from_shared(s)?; - - return Ok(Uri { - scheme: Scheme::empty(), - authority: authority, - path_and_query: PathAndQuery::empty(), - }); - } - }, - _ => {} - } - - if s[0] == b'/' { - return Ok(Uri { - scheme: Scheme::empty(), - authority: Authority::empty(), - path_and_query: PathAndQuery::from_shared(s)?, - }); - } - - parse_full(s) + TryFrom::try_from(s) } /// Convert a `Uri` from a static string. @@ -679,6 +633,80 @@ impl Uri { } } +impl TryFrom for Uri { + type Error = InvalidUriBytes; + + /// Attempt to convert a `Uri` from `Bytes` + /// + /// # Examples + /// + /// ``` + /// # extern crate http; + /// # use http::uri::*; + /// extern crate bytes; + /// + /// use std::convert::TryFrom; + /// use bytes::Bytes; + /// + /// # pub fn main() { + /// let bytes = Bytes::from("http://example.com/foo"); + /// let uri = Uri::try_from(bytes).unwrap(); + /// + /// assert_eq!(uri.host().unwrap(), "example.com"); + /// assert_eq!(uri.path(), "/foo"); + /// # } + /// ``` + fn try_from(s: Bytes) -> Result { + use self::ErrorKind::*; + + if s.len() > MAX_LEN { + return Err(TooLong.into()); + } + + match s.len() { + 0 => { + return Err(Empty.into()); + } + 1 => match s[0] { + b'/' => { + return Ok(Uri { + scheme: Scheme::empty(), + authority: Authority::empty(), + path_and_query: PathAndQuery::slash(), + }); + } + b'*' => { + return Ok(Uri { + scheme: Scheme::empty(), + authority: Authority::empty(), + path_and_query: PathAndQuery::star(), + }); + } + _ => { + let authority = Authority::from_shared(s)?; + + return Ok(Uri { + scheme: Scheme::empty(), + authority: authority, + path_and_query: PathAndQuery::empty(), + }); + } + }, + _ => {} + } + + if s[0] == b'/' { + return Ok(Uri { + scheme: Scheme::empty(), + authority: Authority::empty(), + path_and_query: PathAndQuery::from_shared(s)?, + }); + } + + parse_full(s) + } +} + impl<'a> HttpTryFrom<&'a str> for Uri { type Error = InvalidUri; diff --git a/src/uri/scheme.rs b/src/uri/scheme.rs index 5dccdf93..4ae9424f 100644 --- a/src/uri/scheme.rs +++ b/src/uri/scheme.rs @@ -1,6 +1,7 @@ // Deprecated in 1.26, needed until our minimum version is >=1.23. #[allow(unused, deprecated)] use std::ascii::AsciiExt; +use std::convert::TryFrom; use std::fmt; use std::hash::{Hash, Hasher}; use std::str::FromStr; @@ -43,8 +44,7 @@ impl Scheme { /// Attempt to convert a `Scheme` from `Bytes` /// - /// This function will be replaced by a `TryFrom` implementation once the - /// trait lands in stable. + /// This function has been replaced by `TryFrom` implementation /// /// # Examples /// @@ -63,16 +63,7 @@ impl Scheme { /// # } /// ``` pub fn from_shared(s: Bytes) -> Result { - use self::Scheme2::*; - - match Scheme2::parse_exact(&s[..]).map_err(InvalidUriBytes)? { - None => Err(ErrorKind::InvalidScheme.into()), - Standard(p) => Ok(Standard(p).into()), - Other(_) => { - let b = unsafe { ByteStr::from_utf8_unchecked(s) }; - Ok(Other(Box::new(b)).into()) - } - } + TryFrom::try_from(s) } pub(super) fn empty() -> Self { @@ -118,6 +109,42 @@ impl HttpTryFrom for Scheme { } } +impl TryFrom for Scheme { + type Error = InvalidUriBytes; + + /// Attempt to convert a `Scheme` from `Bytes` + /// + /// # Examples + /// + /// ``` + /// # extern crate http; + /// # use http::uri::*; + /// extern crate bytes; + /// + /// use std::convert::TryFrom; + /// use bytes::Bytes; + /// + /// # pub fn main() { + /// let bytes = Bytes::from("http"); + /// let scheme = Scheme::try_from(bytes).unwrap(); + /// + /// assert_eq!(scheme.as_str(), "http"); + /// # } + /// ``` + fn try_from(s: Bytes) -> Result { + use self::Scheme2::*; + + match Scheme2::parse_exact(&s[..]).map_err(InvalidUriBytes)? { + None => Err(ErrorKind::InvalidScheme.into()), + Standard(p) => Ok(Standard(p).into()), + Other(_) => { + let b = unsafe { ByteStr::from_utf8_unchecked(s) }; + Ok(Other(Box::new(b)).into()) + } + } + } +} + impl<'a> HttpTryFrom<&'a [u8]> for Scheme { type Error = InvalidUri; #[inline]