refactor(headers): Improve docs, fix nits, make formatting faster

src/header/parsing.rs now uses unsafe get_unchecked() again, I don't
know why it was removed.
This commit is contained in:
Pyfisch
2015-05-03 11:21:15 +02:00
parent b916a7b18c
commit 66d54d03e7
21 changed files with 187 additions and 96 deletions

View File

@@ -2,7 +2,7 @@ use unicase::UniCase;
header! { header! {
#[doc="`Access-Control-Allow-Headers` header, part of"] #[doc="`Access-Control-Allow-Headers` header, part of"]
#[doc="[CORS](www.w3.org/TR/cors/#access-control-allow-headers-response-header)"] #[doc="[CORS](http://www.w3.org/TR/cors/#access-control-allow-headers-response-header)"]
#[doc=""] #[doc=""]
#[doc="The `Access-Control-Allow-Headers` header indicates, as part of the"] #[doc="The `Access-Control-Allow-Headers` header indicates, as part of the"]
#[doc="response to a preflight request, which header field names can be used"] #[doc="response to a preflight request, which header field names can be used"]

View File

@@ -2,7 +2,7 @@ use method::Method;
header! { header! {
#[doc="`Access-Control-Allow-Methods` header, part of"] #[doc="`Access-Control-Allow-Methods` header, part of"]
#[doc="[CORS](www.w3.org/TR/cors/#access-control-allow-methods-response-header)"] #[doc="[CORS](http://www.w3.org/TR/cors/#access-control-allow-methods-response-header)"]
#[doc=""] #[doc=""]
#[doc="The `Access-Control-Allow-Methods` header indicates, as part of the"] #[doc="The `Access-Control-Allow-Methods` header indicates, as part of the"]
#[doc="response to a preflight request, which methods can be used during the"] #[doc="response to a preflight request, which methods can be used during the"]

View File

@@ -1,6 +1,6 @@
header! { header! {
#[doc="`Access-Control-Max-Age` header, part of"] #[doc="`Access-Control-Max-Age` header, part of"]
#[doc="[CORS](www.w3.org/TR/cors/#access-control-max-age-response-header)"] #[doc="[CORS](http://www.w3.org/TR/cors/#access-control-max-age-response-header)"]
#[doc=""] #[doc=""]
#[doc="The `Access-Control-Max-Age` header indicates how long the results of a"] #[doc="The `Access-Control-Max-Age` header indicates how long the results of a"]
#[doc="preflight request can be cached in a preflight result cache."] #[doc="preflight request can be cached in a preflight result cache."]

View File

@@ -2,7 +2,7 @@ use unicase::UniCase;
header! { header! {
#[doc="`Access-Control-Request-Headers` header, part of"] #[doc="`Access-Control-Request-Headers` header, part of"]
#[doc="[CORS](www.w3.org/TR/cors/#access-control-request-headers-request-header)"] #[doc="[CORS](http://www.w3.org/TR/cors/#access-control-request-headers-request-header)"]
#[doc=""] #[doc=""]
#[doc="The `Access-Control-Request-Headers` header indicates which headers will"] #[doc="The `Access-Control-Request-Headers` header indicates which headers will"]
#[doc="be used in the actual request as part of the preflight request."] #[doc="be used in the actual request as part of the preflight request."]

View File

@@ -2,7 +2,7 @@ use method::Method;
header! { header! {
#[doc="`Access-Control-Request-Method` header, part of"] #[doc="`Access-Control-Request-Method` header, part of"]
#[doc="[CORS](www.w3.org/TR/cors/#access-control-request-method-request-header)"] #[doc="[CORS](http://www.w3.org/TR/cors/#access-control-request-method-request-header)"]
#[doc=""] #[doc=""]
#[doc="The `Access-Control-Request-Method` header indicates which method will be"] #[doc="The `Access-Control-Request-Method` header indicates which method will be"]
#[doc="used in the actual request as part of the preflight request."] #[doc="used in the actual request as part of the preflight request."]

View File

@@ -1,11 +1,25 @@
use std::any::Any; use std::any::Any;
use std::fmt; use std::fmt::{self, Display};
use std::str::{FromStr, from_utf8}; use std::str::{FromStr, from_utf8};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use serialize::base64::{ToBase64, FromBase64, Standard, Config, Newline}; use serialize::base64::{ToBase64, FromBase64, Standard, Config, Newline};
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
/// The `Authorization` header field. /// `Authorization` header, defined in [RFC7235](https://tools.ietf.org/html/rfc7235#section-4.2)
///
/// The `Authorization` header field allows a user agent to authenticate
/// itself with an origin server -- usually, but not necessarily, after
/// receiving a 401 (Unauthorized) response. Its value consists of
/// credentials containing the authentication information of the user
/// agent for the realm of the resource being requested.
///
/// # ABNF
/// ```plain
/// Authorization = credentials
/// ```
///
/// # Example values
/// * `Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==`
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub struct Authorization<S: Scheme>(pub S); pub struct Authorization<S: Scheme>(pub S);
@@ -69,7 +83,7 @@ impl Scheme for String {
} }
fn fmt_scheme(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt_scheme(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f) Display::fmt(self, f)
} }
} }
@@ -97,12 +111,12 @@ impl Scheme for Basic {
if let Some(ref pass) = self.password { if let Some(ref pass) = self.password {
text.push_str(&pass[..]); text.push_str(&pass[..]);
} }
write!(f, "{}", text.as_bytes().to_base64(Config { f.write_str(&text.as_bytes().to_base64(Config {
char_set: Standard, char_set: Standard,
newline: Newline::CRLF, newline: Newline::CRLF,
pad: true, pad: true,
line_length: None line_length: None
})) })[..])
} }
} }

View File

@@ -3,7 +3,23 @@ use std::str::FromStr;
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use header::parsing::{from_one_comma_delimited, fmt_comma_delimited}; use header::parsing::{from_one_comma_delimited, fmt_comma_delimited};
/// The Cache-Control header. /// `Cache-Control` header, defined in [RFC7234](https://tools.ietf.org/html/rfc7234#section-5.2)
///
/// The `Cache-Control` header field is used to specify directives for
/// caches along the request/response chain. Such cache directives are
/// unidirectional in that the presence of a directive in a request does
/// not imply that the same directive is to be given in the response.
///
/// # ABNF
/// ```plain
/// Cache-Control = 1#cache-directive
/// cache-directive = token [ "=" ( token / quoted-string ) ]
/// ```
///
/// # Example values
/// * `no-cache`
/// * `private, community="UCI"`
/// * `max-age=30`
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
pub struct CacheControl(pub Vec<CacheDirective>); pub struct CacheControl(pub Vec<CacheDirective>);
@@ -28,8 +44,8 @@ impl Header for CacheControl {
} }
impl HeaderFormat for CacheControl { impl HeaderFormat for CacheControl {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt_comma_delimited(fmt, &self[..]) fmt_comma_delimited(f, &self[..])
} }
} }

View File

@@ -1,12 +1,29 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt; use std::fmt::{self, Display};
use std::str::FromStr; use std::str::FromStr;
use header::parsing::{from_comma_delimited, fmt_comma_delimited}; use header::parsing::{from_comma_delimited, fmt_comma_delimited};
use unicase::UniCase; use unicase::UniCase;
pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader}; pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader};
/// The `Connection` header. /// `Connection` header, defined in [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.1)
///
/// The `Connection` header field allows the sender to indicate desired
/// control options for the current connection. In order to avoid
/// confusing downstream recipients, a proxy or gateway MUST remove or
/// replace any received connection options before forwarding the
/// message.
///
/// # ABNF
/// ```plain
/// Connection = 1#connection-option
/// connection-option = token
/// ```
///
/// # Example values
/// * `close`
/// * `upgrade`
/// * `keep-alive`
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub struct Connection(pub Vec<ConnectionOption>); pub struct Connection(pub Vec<ConnectionOption>);
@@ -33,20 +50,20 @@ pub enum ConnectionOption {
impl FromStr for ConnectionOption { impl FromStr for ConnectionOption {
type Err = (); type Err = ();
fn from_str(s: &str) -> Result<ConnectionOption, ()> { fn from_str(s: &str) -> Result<ConnectionOption, ()> {
match s { Ok(match s {
"keep-alive" => Ok(KeepAlive), "keep-alive" => KeepAlive,
"close" => Ok(Close), "close" => Close,
s => Ok(ConnectionHeader(UniCase(s.to_string()))) s => ConnectionHeader(UniCase(s.to_string())),
} })
} }
} }
impl fmt::Display for ConnectionOption { impl Display for ConnectionOption {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", match *self { f.write_str(match *self {
KeepAlive => "keep-alive", KeepAlive => "keep-alive",
Close => "close", Close => "close",
ConnectionHeader(UniCase(ref s)) => s.as_ref() ConnectionHeader(UniCase(ref s)) => s,
}) })
} }
} }
@@ -62,13 +79,12 @@ impl Header for Connection {
} }
impl HeaderFormat for Connection { impl HeaderFormat for Connection {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Connection(ref parts) = *self; let Connection(ref parts) = *self;
fmt_comma_delimited(fmt, &parts[..]) fmt_comma_delimited(f, &parts[..])
} }
} }
bench_header!(close, Connection, { vec![b"close".to_vec()] }); bench_header!(close, Connection, { vec![b"close".to_vec()] });
bench_header!(keep_alive, Connection, { vec![b"keep-alive".to_vec()] }); bench_header!(keep_alive, Connection, { vec![b"keep-alive".to_vec()] });
bench_header!(header, Connection, { vec![b"authorization".to_vec()] }); bench_header!(header, Connection, { vec![b"authorization".to_vec()] });

View File

@@ -1,18 +1,22 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt; use std::fmt::{self, Display};
use std::str::from_utf8; use std::str::from_utf8;
use cookie::Cookie as CookiePair; use cookie::Cookie as CookiePair;
use cookie::CookieJar; use cookie::CookieJar;
/// The `Cookie` header. Defined in [RFC6265](tools.ietf.org/html/rfc6265#section-5.4): /// `Cookie` header, defined in [RFC6265](http://tools.ietf.org/html/rfc6265#section-5.4)
/// ///
/// > If the user agent does attach a Cookie header field to an HTTP /// If the user agent does attach a Cookie header field to an HTTP
/// > request, the user agent must send the cookie-string /// request, the user agent must send the cookie-string
/// > as the value of the header field. /// as the value of the header field.
/// ///
/// > When the user agent generates an HTTP request, the user agent MUST NOT /// When the user agent generates an HTTP request, the user agent MUST NOT
/// > attach more than one Cookie header field. /// attach more than one Cookie header field.
///
/// # Example values
/// * `SID=31d4d96e407aad42`
/// * `SID=31d4d96e407aad42; lang=en-US`
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub struct Cookie(pub Vec<CookiePair>); pub struct Cookie(pub Vec<CookiePair>);
@@ -48,13 +52,13 @@ impl Header for Cookie {
} }
impl HeaderFormat for Cookie { impl HeaderFormat for Cookie {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
let cookies = &self.0; let cookies = &self.0;
for (i, cookie) in cookies.iter().enumerate() { for (i, cookie) in cookies.iter().enumerate() {
if i != 0 { if i != 0 {
try!(fmt.write_str("; ")); try!(f.write_str("; "));
} }
try!(write!(fmt, "{}", cookie.pair())); try!(Display::fmt(&cookie.pair(), f));
} }
Ok(()) Ok(())
} }

View File

@@ -65,10 +65,10 @@ impl Header for Host {
} }
impl HeaderFormat for Host { impl HeaderFormat for Host {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.port { match self.port {
None | Some(80) | Some(443) => write!(fmt, "{}", self.hostname), None | Some(80) | Some(443) => f.write_str(&self.hostname[..]),
Some(port) => write!(fmt, "{}:{}", self.hostname, port) Some(port) => write!(f, "{}:{}", self.hostname, port)
} }
} }
} }
@@ -97,4 +97,3 @@ mod tests {
} }
bench_header!(bench, Host, { vec![b"foo.com:3000".to_vec()] }); bench_header!(bench, Host, { vec![b"foo.com:3000".to_vec()] });

View File

@@ -1,4 +1,5 @@
use header::{self, EntityTag, HttpDate}; use std::fmt::{self, Display};
use header::{self, Header, HeaderFormat, EntityTag, HttpDate};
/// `If-Range` header, defined in [RFC7233](http://tools.ietf.org/html/rfc7233#section-3.2) /// `If-Range` header, defined in [RFC7233](http://tools.ietf.org/html/rfc7233#section-3.2)
/// ///
@@ -31,7 +32,7 @@ pub enum IfRange {
Date(HttpDate), Date(HttpDate),
} }
impl header::Header for IfRange { impl Header for IfRange {
fn header_name() -> &'static str { fn header_name() -> &'static str {
"If-Range" "If-Range"
} }
@@ -48,18 +49,17 @@ impl header::Header for IfRange {
} }
} }
impl header::HeaderFormat for IfRange { impl HeaderFormat for IfRange {
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match self { match self {
&IfRange::EntityTag(ref x) => write!(f, "{}", x), &IfRange::EntityTag(ref x) => Display::fmt(x, f),
&IfRange::Date(ref x) => write!(f, "{}", x), &IfRange::Date(ref x) => Display::fmt(x, f),
} }
} }
} }
impl ::std::fmt::Display for IfRange { impl Display for IfRange {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use header::HeaderFormat;
self.fmt_header(f) self.fmt_header(f)
} }
} }

View File

@@ -258,7 +258,7 @@ macro_rules! header {
impl $crate::header::HeaderFormat for $id { impl $crate::header::HeaderFormat for $id {
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match *self { match *self {
$id::Any => write!(f, "*"), $id::Any => f.write_str("*"),
$id::Items(ref fields) => $crate::header::parsing::fmt_comma_delimited(f, &fields[..]) $id::Items(ref fields) => $crate::header::parsing::fmt_comma_delimited(f, &fields[..])
} }
} }

View File

@@ -42,10 +42,10 @@ impl Header for Pragma {
impl HeaderFormat for Pragma { impl HeaderFormat for Pragma {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { f.write_str(match *self {
Pragma::NoCache => write!(f, "no-cache"), Pragma::NoCache => "no-cache",
Pragma::Ext(ref string) => write!(f, "{}", string), Pragma::Ext(ref string) => &string[..],
} })
} }
} }

View File

@@ -1,15 +1,59 @@
use header::{Header, HeaderFormat}; use header::{Header, HeaderFormat};
use std::fmt; use std::fmt::{self, Display};
use std::str::from_utf8; use std::str::from_utf8;
use cookie::Cookie; use cookie::Cookie;
use cookie::CookieJar; use cookie::CookieJar;
/// The `Set-Cookie` header /// `Set-Cookie` header, defined [RFC6265](http://tools.ietf.org/html/rfc6265#section-4.1)
///
/// The Set-Cookie HTTP response header is used to send cookies from the
/// server to the user agent.
/// ///
/// Informally, the Set-Cookie response header contains the header name /// Informally, the Set-Cookie response header contains the header name
/// "Set-Cookie" followed by a ":" and a cookie. Each cookie begins with /// "Set-Cookie" followed by a ":" and a cookie. Each cookie begins with
/// a name-value-pair, followed by zero or more attribute-value pairs. /// a name-value-pair, followed by zero or more attribute-value pairs.
///
/// # ABNF
/// ```plain
/// set-cookie-header = "Set-Cookie:" SP set-cookie-string
/// set-cookie-string = cookie-pair *( ";" SP cookie-av )
/// cookie-pair = cookie-name "=" cookie-value
/// cookie-name = token
/// cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
/// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
/// ; US-ASCII characters excluding CTLs,
/// ; whitespace DQUOTE, comma, semicolon,
/// ; and backslash
/// token = <token, defined in [RFC2616], Section 2.2>
///
/// cookie-av = expires-av / max-age-av / domain-av /
/// path-av / secure-av / httponly-av /
/// extension-av
/// expires-av = "Expires=" sane-cookie-date
/// sane-cookie-date = <rfc1123-date, defined in [RFC2616], Section 3.3.1>
/// max-age-av = "Max-Age=" non-zero-digit *DIGIT
/// ; In practice, both expires-av and max-age-av
/// ; are limited to dates representable by the
/// ; user agent.
/// non-zero-digit = %x31-39
/// ; digits 1 through 9
/// domain-av = "Domain=" domain-value
/// domain-value = <subdomain>
/// ; defined in [RFC1034], Section 3.5, as
/// ; enhanced by [RFC1123], Section 2.1
/// path-av = "Path=" path-value
/// path-value = <any CHAR except CTLs or ";">
/// secure-av = "Secure"
/// httponly-av = "HttpOnly"
/// extension-av = <any CHAR except CTLs or ";">
/// ```
///
/// # Example values
/// * `SID=31d4d96e407aad42`
/// * `lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT`
/// * `lang=; Expires=Sun, 06 Nov 1994 08:49:37 GMT`
/// * `lang=en-US; Path=/; Domain=example.com`
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub struct SetCookie(pub Vec<Cookie>); pub struct SetCookie(pub Vec<Cookie>);
@@ -46,7 +90,7 @@ impl HeaderFormat for SetCookie {
if i != 0 { if i != 0 {
try!(f.write_str("\r\nSet-Cookie: ")); try!(f.write_str("\r\nSet-Cookie: "));
} }
try!(write!(f, "{}", cookie)); try!(Display::fmt(cookie, f));
} }
Ok(()) Ok(())
} }

View File

@@ -94,12 +94,12 @@ fn parse<H: Header + HeaderFormat>(raw: &Vec<Vec<u8>>) -> Option<Box<HeaderForma
} }
impl fmt::Display for Item { impl fmt::Display for Item {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.raw { match *self.raw {
Some(ref raw) => { Some(ref raw) => {
for part in raw.iter() { for part in raw.iter() {
match from_utf8(&part[..]) { match from_utf8(&part[..]) {
Ok(s) => try!(fmt.write_str(s)), Ok(s) => try!(f.write_str(s)),
Err(e) => { Err(e) => {
error!("raw header value is not utf8. header={:?}, error={:?}", part, e); error!("raw header value is not utf8. header={:?}, error={:?}", part, e);
return Err(fmt::Error); return Err(fmt::Error);
@@ -108,7 +108,7 @@ impl fmt::Display for Item {
} }
Ok(()) Ok(())
}, },
None => fmt::Display::fmt(&unsafe { self.typed.one() }, fmt) None => fmt::Display::fmt(&unsafe { self.typed.one() }, f)
} }
} }
} }

View File

@@ -57,7 +57,7 @@ pub trait HeaderFormat: fmt::Debug + HeaderClone + Any + Typeable + Send + Sync
/// ///
/// This method is not allowed to introduce an Err not produced /// This method is not allowed to introduce an Err not produced
/// by the passed-in Formatter. /// by the passed-in Formatter.
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result; fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result;
} }
@@ -224,21 +224,21 @@ impl Headers {
} }
impl fmt::Display for Headers { impl fmt::Display for Headers {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for header in self.iter() { for header in self.iter() {
try!(write!(fmt, "{}\r\n", header)); try!(write!(f, "{}\r\n", header));
} }
Ok(()) Ok(())
} }
} }
impl fmt::Debug for Headers { impl fmt::Debug for Headers {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(fmt.write_str("Headers { ")); try!(f.write_str("Headers { "));
for header in self.iter() { for header in self.iter() {
try!(write!(fmt, "{:?}, ", header)); try!(write!(f, "{:?}, ", header));
} }
try!(fmt.write_str("}")); try!(f.write_str("}"));
Ok(()) Ok(())
} }
} }
@@ -292,8 +292,8 @@ impl<'a> fmt::Display for HeaderView<'a> {
} }
impl<'a> fmt::Debug for HeaderView<'a> { impl<'a> fmt::Debug for HeaderView<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, fmt) fmt::Display::fmt(self, f)
} }
} }
@@ -315,8 +315,8 @@ impl<'a> FromIterator<HeaderView<'a>> for Headers {
impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) { impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) {
#[inline] #[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt_header(fmt) (**self).fmt_header(f)
} }
} }
@@ -353,14 +353,14 @@ impl Deref for CowStr {
} }
impl fmt::Debug for CowStr { impl fmt::Debug for CowStr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, fmt) fmt::Debug::fmt(&self.0, f)
} }
} }
impl fmt::Display for CowStr { impl fmt::Display for CowStr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, fmt) fmt::Display::fmt(&self.0, f)
} }
} }
@@ -460,9 +460,9 @@ mod tests {
} }
impl HeaderFormat for CrazyLength { impl HeaderFormat for CrazyLength {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
let CrazyLength(ref opt, ref value) = *self; let CrazyLength(ref opt, ref value) = *self;
write!(fmt, "{:?}, {:?}", opt, value) write!(f, "{:?}, {:?}", opt, value)
} }
} }

View File

@@ -1,7 +1,7 @@
//! Utility functions for Header implementations. //! Utility functions for Header implementations.
use std::str; use std::str;
use std::fmt; use std::fmt::{self, Display};
/// Reads a single raw string when parsing a header /// Reads a single raw string when parsing a header
pub fn from_one_raw_str<T: str::FromStr>(raw: &[Vec<u8>]) -> Option<T> { pub fn from_one_raw_str<T: str::FromStr>(raw: &[Vec<u8>]) -> Option<T> {
@@ -9,7 +9,7 @@ pub fn from_one_raw_str<T: str::FromStr>(raw: &[Vec<u8>]) -> Option<T> {
return None; return None;
} }
// we JUST checked that raw.len() == 1, so raw[0] WILL exist. // we JUST checked that raw.len() == 1, so raw[0] WILL exist.
if let Ok(s) = str::from_utf8(&raw[0][..]) { if let Ok(s) = str::from_utf8(& unsafe { raw.get_unchecked(0) }[..]) {
if s != "" { if s != "" {
return str::FromStr::from_str(s).ok(); return str::FromStr::from_str(s).ok();
} }
@@ -24,7 +24,7 @@ pub fn from_comma_delimited<T: str::FromStr>(raw: &[Vec<u8>]) -> Option<Vec<T>>
return None; return None;
} }
// we JUST checked that raw.len() == 1, so raw[0] WILL exist. // we JUST checked that raw.len() == 1, so raw[0] WILL exist.
from_one_comma_delimited(&raw[0][..]) from_one_comma_delimited(& unsafe { raw.get_unchecked(0) }[..])
} }
/// Reads a comma-delimited raw string into a Vec. /// Reads a comma-delimited raw string into a Vec.
@@ -45,12 +45,12 @@ pub fn from_one_comma_delimited<T: str::FromStr>(raw: &[u8]) -> Option<Vec<T>> {
} }
/// Format an array into a comma-delimited string. /// Format an array into a comma-delimited string.
pub fn fmt_comma_delimited<T: fmt::Display>(f: &mut fmt::Formatter, parts: &[T]) -> fmt::Result { pub fn fmt_comma_delimited<T: Display>(f: &mut fmt::Formatter, parts: &[T]) -> fmt::Result {
for (i, part) in parts.iter().enumerate() { for (i, part) in parts.iter().enumerate() {
if i > 0 { if i != 0 {
try!(write!(f, ", ")); try!(f.write_str(", "));
} }
try!(write!(f, "{}", part)); try!(Display::fmt(part, f));
} }
Ok(()) Ok(())
} }

View File

@@ -97,8 +97,8 @@ impl Charset {
} }
impl Display for Charset { impl Display for Charset {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.name()) f.write_str(self.name())
} }
} }

View File

@@ -24,8 +24,8 @@ pub enum Encoding {
} }
impl fmt::Display for Encoding { impl fmt::Display for Encoding {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(match *self { f.write_str(match *self {
Chunked => "chunked", Chunked => "chunked",
Gzip => "gzip", Gzip => "gzip",
Deflate => "deflate", Deflate => "deflate",

View File

@@ -103,10 +103,10 @@ impl EntityTag {
} }
impl Display for EntityTag { impl Display for EntityTag {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.weak { match self.weak {
true => write!(fmt, "W/\"{}\"", self.tag), true => write!(f, "W/\"{}\"", self.tag),
false => write!(fmt, "\"{}\"", self.tag), false => write!(f, "\"{}\"", self.tag),
} }
} }
} }
@@ -116,10 +116,8 @@ impl FromStr for EntityTag {
fn from_str(s: &str) -> Result<EntityTag, ()> { fn from_str(s: &str) -> Result<EntityTag, ()> {
let length: usize = s.len(); let length: usize = s.len();
let slice = &s[..]; let slice = &s[..];
// Early exits: // Early exits if it doesn't terminate in a DQUOTE.
// 1. The string is empty, or, if !slice.ends_with('"') {
// 2. it doesn't terminate in a DQUOTE.
if slice.is_empty() || !slice.ends_with('"') {
return Err(()); return Err(());
} }
// The etag is weak if its first char is not a DQUOTE. // The etag is weak if its first char is not a DQUOTE.

View File

@@ -36,7 +36,7 @@ impl FromStr for Language {
impl fmt::Display for Language { impl fmt::Display for Language {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{}", self.primary)); try!(f.write_str(&self.primary[..]));
match self.sub { match self.sub {
Some(ref s) => write!(f, "-{}", s), Some(ref s) => write!(f, "-{}", s),
None => Ok(()) None => Ok(())