From 2827c9bbe510d4638fa87dd06e2da608edb43cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Tue, 25 May 2021 10:08:22 +0200 Subject: [PATCH] optimize Method --- CHANGELOG.md | 4 +- README.md | 2 + src/enums.rs | 111 +++++++++++++++++++++++++++++++-------------------- src/lib.rs | 2 +- 4 files changed, 72 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d31d07d..ab2022d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,9 @@ # 0.3.0 - Added lifetime parameter to `HttpMethod` -- Changed `HttpMethod::OTHER(&'static str)` to `HttpMethod::OTHER(Cow<'a, str>)` +- Changed `HttpMethod` to `HttpMethod<'a>(Cow<'a, str>)` - Added unit tests -- Converted one Into impl to From +- Added support for the `http` crate's `Method` struct (optional feature) # 0.2.4 diff --git a/README.md b/README.md index 786396c..fcf044c 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,5 @@ Rust implementation of Digest Auth hashing algorithms, as defined in IETF RFC 2069, 2617, and 7616. This crate provides the authentication header parsing and generation code. + +Please see the docs and tests for examples. diff --git a/src/enums.rs b/src/enums.rs index 6be2f7e..0412e98 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -170,11 +170,19 @@ impl Display for Charset { /// HTTP method (used when generating the response hash for some Qop options) #[derive(Debug, PartialEq, Clone)] -pub enum HttpMethod<'a> { - GET, - POST, - HEAD, - OTHER(Cow<'a, str>), +pub struct HttpMethod<'a>(pub Cow<'a, str>); + +// Well-known methods are provided as convenient associated constants +impl<'a> HttpMethod<'a> { + pub const GET : Self = HttpMethod(Cow::Borrowed("GET")); + pub const POST : Self = HttpMethod(Cow::Borrowed("POST")); + pub const PUT : Self = HttpMethod(Cow::Borrowed("PUT")); + pub const DELETE : Self = HttpMethod(Cow::Borrowed("DELETE")); + pub const HEAD : Self = HttpMethod(Cow::Borrowed("HEAD")); + pub const OPTIONS : Self = HttpMethod(Cow::Borrowed("OPTIONS")); + pub const CONNECT : Self = HttpMethod(Cow::Borrowed("CONNECT")); + pub const PATCH : Self = HttpMethod(Cow::Borrowed("PATCH")); + pub const TRACE : Self = HttpMethod(Cow::Borrowed("TRACE")); } impl<'a> Default for HttpMethod<'a> { @@ -186,66 +194,61 @@ impl<'a> Default for HttpMethod<'a> { impl<'a> Display for HttpMethod<'a> { /// Convert to uppercase string fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.write_str(match self { - HttpMethod::GET => "GET", - HttpMethod::POST => "POST", - HttpMethod::HEAD => "HEAD", - HttpMethod::OTHER(s) => s, - }) + f.write_str(&self.0) } } impl<'a> From<&'a str> for HttpMethod<'a> { fn from(s: &'a str) -> Self { - match s { - "GET" => HttpMethod::GET, - "POST" => HttpMethod::POST, - "HEAD" => HttpMethod::HEAD, - s => HttpMethod::OTHER(Cow::Borrowed(s)), - } + Self(s.into()) } } impl<'a> From<&'a [u8]> for HttpMethod<'a> { fn from(s: &'a [u8]) -> Self { - String::from_utf8_lossy(s).into() + Self(String::from_utf8_lossy(s).into()) } } impl<'a> From for HttpMethod<'a> { fn from(s: String) -> Self { - match &s[..] { - "GET" => HttpMethod::GET, - "POST" => HttpMethod::POST, - "HEAD" => HttpMethod::HEAD, - _ => HttpMethod::OTHER(Cow::Owned(s)), - } + Self(s.into()) } } impl<'a> From> for HttpMethod<'a> { fn from(s: Cow<'a, str>) -> Self { - match &s[..] { - "GET" => HttpMethod::GET, - "POST" => HttpMethod::POST, - "HEAD" => HttpMethod::HEAD, - _ => HttpMethod::OTHER(s), - } + Self(s) } } #[cfg(feature = "http")] impl From for HttpMethod<'static> { fn from(method: http::Method) -> Self { - match method { - http::Method::GET => HttpMethod::GET, - http::Method::POST => HttpMethod::POST, - http::Method::HEAD => HttpMethod::HEAD, - other => HttpMethod::OTHER(other.to_string().into()), + match method.as_str() { + // Avoid cloning when possible + "GET" => Self::GET, + "POST" => Self::POST, + "PUT" => Self::PUT, + "DELETE" => Self::DELETE, + "HEAD" => Self::HEAD, + "OPTIONS" => Self::OPTIONS, + "CONNECT" => Self::CONNECT, + "PATCH" => Self::PATCH, + "TRACE" => Self::TRACE, + // Clone custom strings. This is inefficient, but the inner string is private + other => Self(other.to_owned().into()) } } } +#[cfg(feature = "http")] +impl<'a> From<&'a http::Method> for HttpMethod<'a> { + fn from(method: &'a http::Method) -> HttpMethod<'a> { + Self(method.as_str().into()) + } +} + #[cfg(test)] mod test { use crate::error::Error::{BadCharset, BadQop, UnknownAlgorithm}; @@ -373,55 +376,75 @@ mod test { // Well known 'static assert_eq!(HttpMethod::GET, "GET".into()); assert_eq!(HttpMethod::POST, "POST".into()); + assert_eq!(HttpMethod::PUT, "PUT".into()); + assert_eq!(HttpMethod::DELETE, "DELETE".into()); assert_eq!(HttpMethod::HEAD, "HEAD".into()); + assert_eq!(HttpMethod::OPTIONS, "OPTIONS".into()); + assert_eq!(HttpMethod::CONNECT, "CONNECT".into()); + assert_eq!(HttpMethod::PATCH, "PATCH".into()); + assert_eq!(HttpMethod::TRACE, "TRACE".into()); // As bytes assert_eq!(HttpMethod::GET, "GET".as_bytes().into()); assert_eq!( - HttpMethod::OTHER(Cow::Borrowed("ěščř")), + HttpMethod(Cow::Borrowed("ěščř")), "ěščř".as_bytes().into() ); assert_eq!( - HttpMethod::OTHER(Cow::Owned("AB�".to_string())), + HttpMethod(Cow::Owned("AB�".to_string())), // Lossy conversion (&[65u8, 66, 156][..]).into() ); // Well known String assert_eq!(HttpMethod::GET, String::from("GET").into()); // Custom String assert_eq!( - HttpMethod::OTHER(Cow::Borrowed("NonsenseMethod")), + HttpMethod(Cow::Borrowed("NonsenseMethod")), "NonsenseMethod".into() ); assert_eq!( - HttpMethod::OTHER(Cow::Owned("NonsenseMethod".to_string())), + HttpMethod(Cow::Owned("NonsenseMethod".to_string())), "NonsenseMethod".to_string().into() ); // Custom Cow assert_eq!(HttpMethod::HEAD, Cow::Borrowed("HEAD").into()); assert_eq!( - HttpMethod::OTHER(Cow::Borrowed("NonsenseMethod")), + HttpMethod(Cow::Borrowed("NonsenseMethod")), Cow::Borrowed("NonsenseMethod").into() ); // to string assert_eq!("GET".to_string(), HttpMethod::GET.to_string()); assert_eq!("POST".to_string(), HttpMethod::POST.to_string()); + assert_eq!("PUT".to_string(), HttpMethod::PUT.to_string()); + assert_eq!("DELETE".to_string(), HttpMethod::DELETE.to_string()); assert_eq!("HEAD".to_string(), HttpMethod::HEAD.to_string()); + assert_eq!("OPTIONS".to_string(), HttpMethod::OPTIONS.to_string()); + assert_eq!("CONNECT".to_string(), HttpMethod::CONNECT.to_string()); + assert_eq!("PATCH".to_string(), HttpMethod::PATCH.to_string()); + assert_eq!("TRACE".to_string(), HttpMethod::TRACE.to_string()); + assert_eq!( "NonsenseMethod".to_string(), - HttpMethod::OTHER(Cow::Borrowed("NonsenseMethod")).to_string() + HttpMethod(Cow::Borrowed("NonsenseMethod")).to_string() ); assert_eq!( "NonsenseMethod".to_string(), - HttpMethod::OTHER(Cow::Owned("NonsenseMethod".to_string())).to_string() + HttpMethod(Cow::Owned("NonsenseMethod".to_string())).to_string() ); } #[cfg(feature = "http")] #[test] fn test_http_crate() { - assert_eq!(HttpMethod::GET, http::Method::GET.into()); + assert_eq!(HttpMethod::GET, http::Method::GET.clone().into()); assert_eq!( - HttpMethod::OTHER(Cow::Owned("BANANA".to_string())), + HttpMethod(Cow::Owned("BANANA".to_string())), http::Method::from_str("BANANA").unwrap().into() ); + + assert_eq!(HttpMethod::GET, (&http::Method::GET).into()); + let x = http::Method::from_str("BANANA").unwrap(); + assert_eq!( + HttpMethod(Cow::Borrowed("BANANA")), + (&x).into() + ); } } diff --git a/src/lib.rs b/src/lib.rs index 2e7bb20..3185d94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,7 +83,7 @@ mod test { let mut prompt = crate::parse(src).unwrap(); let answer = prompt.respond(&context).unwrap(); - let str = answer.to_string().replace(", ", ",\n "); + let str = answer.to_string().replace(", ", ",\n "); // This is only for easier reading assert_eq!( str,