feat(lib): switch to non-blocking (asynchronous) IO

BREAKING CHANGE: This breaks a lot of the Client and Server APIs.
  Check the documentation for how Handlers can be used for asynchronous
  events.
This commit is contained in:
Sean McArthur
2016-05-03 20:45:43 -07:00
parent 1ec56fe6b6
commit d35992d019
65 changed files with 5599 additions and 5023 deletions

View File

@@ -1,7 +1,7 @@
use std::fmt::{self, Display};
use std::str;
use unicase::UniCase;
use header::{Header, HeaderFormat};
use header::{Header};
/// `Access-Control-Allow-Credentials` header, part of
/// [CORS](http://www.w3.org/TR/cors/#access-control-allow-headers-response-header)
@@ -62,9 +62,7 @@ impl Header for AccessControlAllowCredentials {
}
Err(::Error::Header)
}
}
impl HeaderFormat for AccessControlAllowCredentials {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("true")
}
@@ -86,4 +84,4 @@ mod test_access_control_allow_credentials {
test_header!(not_bool, vec![b"false"], None);
test_header!(only_single, vec![b"true", b"true"], None);
test_header!(no_gibberish, vec!["\u{645}\u{631}\u{62d}\u{628}\u{627}".as_bytes()], None);
}
}

View File

@@ -1,6 +1,6 @@
use std::fmt::{self, Display};
use header::{Header, HeaderFormat};
use header::{Header};
/// The `Access-Control-Allow-Origin` response header,
/// part of [CORS](http://www.w3.org/TR/cors/#access-control-allow-origin-response-header)
@@ -70,9 +70,7 @@ impl Header for AccessControlAllowOrigin {
_ => AccessControlAllowOrigin::Value(try!(String::from_utf8(value.clone())))
})
}
}
impl HeaderFormat for AccessControlAllowOrigin {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AccessControlAllowOrigin::Any => f.write_str("*"),

View File

@@ -3,7 +3,7 @@ use std::fmt::{self, Display};
use std::str::{FromStr, from_utf8};
use std::ops::{Deref, DerefMut};
use serialize::base64::{ToBase64, FromBase64, Standard, Config, Newline};
use header::{Header, HeaderFormat};
use header::{Header};
/// `Authorization` header, defined in [RFC7235](https://tools.ietf.org/html/rfc7235#section-4.2)
///
@@ -97,9 +97,7 @@ impl<S: Scheme + Any> Header for Authorization<S> where <S as FromStr>::Err: 'st
}
}
}
}
impl<S: Scheme + Any> HeaderFormat for Authorization<S> where <S as FromStr>::Err: 'static {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(scheme) = <S as Scheme>::scheme() {
try!(write!(f, "{} ", scheme))

View File

@@ -1,6 +1,6 @@
use std::fmt;
use std::str::FromStr;
use header::{Header, HeaderFormat};
use header::Header;
use header::parsing::{from_comma_delimited, fmt_comma_delimited};
/// `Cache-Control` header, defined in [RFC7234](https://tools.ietf.org/html/rfc7234#section-5.2)
@@ -62,9 +62,7 @@ impl Header for CacheControl {
Err(::Error::Header)
}
}
}
impl HeaderFormat for CacheControl {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt_comma_delimited(f, &self[..])
}

View File

@@ -11,7 +11,7 @@ use std::fmt;
use unicase::UniCase;
use url::percent_encoding;
use header::{Header, HeaderFormat, parsing};
use header::{Header, parsing};
use header::parsing::{parse_extended_value, HTTP_VALUE};
use header::shared::Charset;
@@ -144,9 +144,7 @@ impl Header for ContentDisposition {
Ok(cd)
})
}
}
impl HeaderFormat for ContentDisposition {
#[inline]
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self, f)

View File

@@ -1,6 +1,6 @@
use std::fmt;
use header::{HeaderFormat, Header, parsing};
use header::{Header, parsing};
/// `Content-Length` header, defined in
/// [RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.2)
@@ -55,9 +55,7 @@ impl Header for ContentLength {
.unwrap_or(Err(::Error::Header))
.map(ContentLength)
}
}
impl HeaderFormat for ContentLength {
#[inline]
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)

View File

@@ -1,4 +1,4 @@
use header::{Header, HeaderFormat, CookiePair, CookieJar};
use header::{Header, CookiePair, CookieJar};
use std::fmt::{self, Display};
use std::str::from_utf8;
@@ -61,9 +61,7 @@ impl Header for Cookie {
Err(::Error::Header)
}
}
}
impl HeaderFormat for Cookie {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
let cookies = &self.0;
for (i, cookie) in cookies.iter().enumerate() {

View File

@@ -3,7 +3,7 @@ use std::str;
use unicase::UniCase;
use header::{Header, HeaderFormat};
use header::{Header};
/// The `Expect` header.
///
@@ -53,9 +53,7 @@ impl Header for Expect {
Err(::Error::Header)
}
}
}
impl HeaderFormat for Expect {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("100-continue")
}

View File

@@ -1,4 +1,4 @@
use header::{Header, HeaderFormat};
use header::{Header};
use std::fmt;
use header::parsing::from_one_raw_str;
@@ -52,9 +52,7 @@ impl Header for Host {
// https://github.com/servo/rust-url/issues/42
let idx = {
let slice = &s[..];
let mut chars = slice.chars();
chars.next();
if chars.next().unwrap() == '[' {
if slice.starts_with('[') {
match slice.rfind(']') {
Some(idx) => {
if slice.len() > idx + 2 {
@@ -86,9 +84,7 @@ impl Header for Host {
})
})
}
}
impl HeaderFormat for Host {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.port {
None | Some(80) | Some(443) => f.write_str(&self.hostname[..]),

View File

@@ -1,5 +1,5 @@
use std::fmt::{self, Display};
use header::{self, Header, HeaderFormat, EntityTag, HttpDate};
use header::{self, Header, EntityTag, HttpDate};
/// `If-Range` header, defined in [RFC7233](http://tools.ietf.org/html/rfc7233#section-3.2)
///
@@ -59,18 +59,16 @@ impl Header for IfRange {
}
fn parse_header(raw: &[Vec<u8>]) -> ::Result<IfRange> {
let etag: ::Result<EntityTag> = header::parsing::from_one_raw_str(raw);
if etag.is_ok() {
return Ok(IfRange::EntityTag(etag.unwrap()));
if let Ok(etag) = etag {
return Ok(IfRange::EntityTag(etag));
}
let date: ::Result<HttpDate> = header::parsing::from_one_raw_str(raw);
if date.is_ok() {
return Ok(IfRange::Date(date.unwrap()));
if let Ok(date) = date {
return Ok(IfRange::Date(date));
}
Err(::Error::Header)
}
}
impl HeaderFormat for IfRange {
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match *self {
IfRange::EntityTag(ref x) => Display::fmt(x, f),

View File

@@ -66,7 +66,7 @@ macro_rules! bench_header(
use test::Bencher;
use super::*;
use header::{Header, HeaderFormatter};
use header::{Header};
#[bench]
fn bench_parse(b: &mut Bencher) {
@@ -79,7 +79,7 @@ macro_rules! bench_header(
#[bench]
fn bench_format(b: &mut Bencher) {
let val: $ty = Header::parse_header(&$value[..]).unwrap();
let fmt = HeaderFormatter(&val);
let fmt = ::header::HeaderFormatter(&val);
b.iter(|| {
format!("{}", fmt);
});
@@ -222,15 +222,13 @@ macro_rules! header {
fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
$crate::header::parsing::from_comma_delimited(raw).map($id)
}
}
impl $crate::header::HeaderFormat for $id {
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
$crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
}
}
impl ::std::fmt::Display for $id {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
use $crate::header::HeaderFormat;
use $crate::header::Header;
self.fmt_header(f)
}
}
@@ -250,15 +248,13 @@ macro_rules! header {
fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
$crate::header::parsing::from_comma_delimited(raw).map($id)
}
}
impl $crate::header::HeaderFormat for $id {
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
$crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
}
}
impl ::std::fmt::Display for $id {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
use $crate::header::HeaderFormat;
use $crate::header::Header;
self.fmt_header(f)
}
}
@@ -277,8 +273,6 @@ macro_rules! header {
fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
$crate::header::parsing::from_one_raw_str(raw).map($id)
}
}
impl $crate::header::HeaderFormat for $id {
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
::std::fmt::Display::fmt(&**self, f)
}
@@ -313,8 +307,6 @@ macro_rules! header {
}
$crate::header::parsing::from_comma_delimited(raw).map($id::Items)
}
}
impl $crate::header::HeaderFormat for $id {
fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match *self {
$id::Any => f.write_str("*"),
@@ -325,7 +317,7 @@ macro_rules! header {
}
impl ::std::fmt::Display for $id {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
use $crate::header::HeaderFormat;
use $crate::header::Header;
self.fmt_header(f)
}
}

View File

@@ -1,7 +1,7 @@
use std::fmt;
use std::ascii::AsciiExt;
use header::{Header, HeaderFormat, parsing};
use header::{Header, parsing};
/// The `Pragma` header defined by HTTP/1.0.
///
@@ -52,9 +52,7 @@ impl Header for Pragma {
}
})
}
}
impl HeaderFormat for Pragma {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
Pragma::NoCache => "no-cache",

View File

@@ -1,6 +1,6 @@
use std::fmt;
use std::str::FromStr;
use header::{Header, HeaderFormat};
use header::{Header};
use header::parsing::{from_comma_delimited, fmt_comma_delimited};
/// `Prefer` header, defined in [RFC7240](http://tools.ietf.org/html/rfc7240)
@@ -64,9 +64,7 @@ impl Header for Prefer {
Err(::Error::Header)
}
}
}
impl HeaderFormat for Prefer {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt_comma_delimited(f, &self[..])
}

View File

@@ -1,5 +1,5 @@
use std::fmt;
use header::{Header, HeaderFormat, Preference};
use header::{Header, Preference};
use header::parsing::{from_comma_delimited, fmt_comma_delimited};
/// `Preference-Applied` header, defined in [RFC7240](http://tools.ietf.org/html/rfc7240)
@@ -61,9 +61,7 @@ impl Header for PreferenceApplied {
Err(::Error::Header)
}
}
}
impl HeaderFormat for PreferenceApplied {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
let preferences: Vec<_> = self.0.iter().map(|pref| match pref {
// The spec ignores parameters in `Preferences-Applied`
@@ -80,7 +78,7 @@ impl HeaderFormat for PreferenceApplied {
#[cfg(test)]
mod tests {
use header::{HeaderFormat, Preference};
use header::{Header, Preference};
use super::*;
#[test]
@@ -90,7 +88,7 @@ mod tests {
"foo".to_owned(),
"bar".to_owned(),
vec![("bar".to_owned(), "foo".to_owned()), ("buz".to_owned(), "".to_owned())]
)]) as &(HeaderFormat + Send + Sync)),
)]) as &(Header + Send + Sync)),
"foo=bar".to_owned()
);
}

View File

@@ -1,7 +1,7 @@
use std::fmt::{self, Display};
use std::str::FromStr;
use header::{Header, HeaderFormat};
use header::Header;
use header::parsing::{from_one_raw_str, from_comma_delimited};
/// `Range` header, defined in [RFC7233](https://tools.ietf.org/html/rfc7233#section-3.1)
@@ -182,9 +182,6 @@ impl Header for Range {
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Range> {
from_one_raw_str(raw)
}
}
impl HeaderFormat for Range {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(self, f)

View File

@@ -1,4 +1,4 @@
use header::{Header, HeaderFormat, CookiePair, CookieJar};
use header::{Header, CookiePair, CookieJar};
use std::fmt::{self, Display};
use std::str::from_utf8;
@@ -104,10 +104,6 @@ impl Header for SetCookie {
}
}
}
impl HeaderFormat for SetCookie {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, cookie) in self.0.iter().enumerate() {
if i != 0 {

View File

@@ -3,7 +3,7 @@ use std::str::{self, FromStr};
use unicase::UniCase;
use header::{Header, HeaderFormat, parsing};
use header::{Header, parsing};
/// `StrictTransportSecurity` header, defined in [RFC6797](https://tools.ietf.org/html/rfc6797)
///
@@ -127,9 +127,7 @@ impl Header for StrictTransportSecurity {
fn parse_header(raw: &[Vec<u8>]) -> ::Result<StrictTransportSecurity> {
parsing::from_one_raw_str(raw)
}
}
impl HeaderFormat for StrictTransportSecurity {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.include_subdomains {
write!(f, "max-age={}; includeSubdomains", self.max_age)

View File

@@ -49,5 +49,12 @@ header! {
}
}
impl TransferEncoding {
/// Constructor for the most common Transfer-Encoding, `chunked`.
pub fn chunked() -> TransferEncoding {
TransferEncoding(vec![Encoding::Chunked])
}
}
bench_header!(normal, TransferEncoding, { vec![b"chunked, gzip".to_vec()] });
bench_header!(ext, TransferEncoding, { vec![b"ext".to_vec()] });

View File

@@ -1,7 +1,6 @@
use std::any::{Any, TypeId};
use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::fmt;
use std::mem;
use std::ops::Deref;
@@ -53,7 +52,7 @@ enum PtrMap<T> {
Many(HashMap<TypeId, T>)
}
impl<V: ?Sized + fmt::Debug + Any + 'static> PtrMapCell<V> {
impl<V: ?Sized + Any + 'static> PtrMapCell<V> {
#[inline]
pub fn new() -> PtrMapCell<V> {
PtrMapCell(UnsafeCell::new(PtrMap::Empty))
@@ -114,12 +113,12 @@ impl<V: ?Sized + fmt::Debug + Any + 'static> PtrMapCell<V> {
let map = &*self.0.get();
match *map {
PtrMap::One(_, ref one) => one,
_ => panic!("not PtrMap::One value, {:?}", *map)
_ => panic!("not PtrMap::One value")
}
}
}
impl<V: ?Sized + fmt::Debug + Any + 'static> Clone for PtrMapCell<V> where Box<V>: Clone {
impl<V: ?Sized + Any + 'static> Clone for PtrMapCell<V> where Box<V>: Clone {
#[inline]
fn clone(&self) -> PtrMapCell<V> {
let cell = PtrMapCell::new();

View File

@@ -4,13 +4,13 @@ use std::fmt;
use std::str::from_utf8;
use super::cell::{OptCell, PtrMapCell};
use header::{Header, HeaderFormat};
use header::{Header};
#[derive(Clone)]
pub struct Item {
raw: OptCell<Vec<Vec<u8>>>,
typed: PtrMapCell<HeaderFormat + Send + Sync>
typed: PtrMapCell<Header + Send + Sync>
}
impl Item {
@@ -23,7 +23,7 @@ impl Item {
}
#[inline]
pub fn new_typed(ty: Box<HeaderFormat + Send + Sync>) -> Item {
pub fn new_typed(ty: Box<Header + Send + Sync>) -> Item {
let map = PtrMapCell::new();
unsafe { map.insert((*ty).get_type(), ty); }
Item {
@@ -52,7 +52,7 @@ impl Item {
&raw[..]
}
pub fn typed<H: Header + HeaderFormat + Any>(&self) -> Option<&H> {
pub fn typed<H: Header + Any>(&self) -> Option<&H> {
let tid = TypeId::of::<H>();
match self.typed.get(tid) {
Some(val) => Some(val),
@@ -68,7 +68,7 @@ impl Item {
}.map(|typed| unsafe { typed.downcast_ref_unchecked() })
}
pub fn typed_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> {
pub fn typed_mut<H: Header>(&mut self) -> Option<&mut H> {
let tid = TypeId::of::<H>();
if self.typed.get_mut(tid).is_none() {
match parse::<H>(self.raw.as_ref().expect("item.raw must exist")) {
@@ -83,11 +83,11 @@ impl Item {
}
#[inline]
fn parse<H: Header + HeaderFormat>(raw: &Vec<Vec<u8>>) ->
::Result<Box<HeaderFormat + Send + Sync>> {
fn parse<H: Header>(raw: &Vec<Vec<u8>>) ->
::Result<Box<Header + Send + Sync>> {
Header::parse_header(&raw[..]).map(|h: H| {
// FIXME: Use Type ascription
let h: Box<HeaderFormat + Send + Sync> = Box::new(h);
let h: Box<Header + Send + Sync> = Box::new(h);
h
})
}

View File

@@ -31,18 +31,17 @@
//! }
//! ```
//!
//! This works well for simple "string" headers. But the header system
//! actually involves 2 parts: parsing, and formatting. If you need to
//! customize either part, you can do so.
//! This works well for simple "string" headers. If you need more control,
//! you can implement the trait directly.
//!
//! ## `Header` and `HeaderFormat`
//! ## Implementing the `Header` trait
//!
//! Consider a Do Not Track header. It can be true or false, but it represents
//! that via the numerals `1` and `0`.
//!
//! ```
//! use std::fmt;
//! use hyper::header::{Header, HeaderFormat};
//! use hyper::header::Header;
//!
//! #[derive(Debug, Clone, Copy)]
//! struct Dnt(bool);
@@ -66,9 +65,7 @@
//! }
//! Err(hyper::Error::Header)
//! }
//! }
//!
//! impl HeaderFormat for Dnt {
//! fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
//! if self.0 {
//! f.write_str("1")
@@ -113,11 +110,11 @@ type HeaderName = UniCase<CowStr>;
///
/// This trait represents the construction and identification of headers,
/// and contains trait-object unsafe methods.
pub trait Header: Clone + Any + Send + Sync {
pub trait Header: HeaderClone + Any + Typeable + Send + Sync {
/// Returns the name of the header field this belongs to.
///
/// This will become an associated constant once available.
fn header_name() -> &'static str;
fn header_name() -> &'static str where Self: Sized;
/// Parse a header from a raw stream of bytes.
///
/// It's possible that a request can include a header field more than once,
@@ -125,35 +122,27 @@ pub trait Header: Clone + Any + Send + Sync {
/// it's not necessarily the case that a Header is *allowed* to have more
/// than one field value. If that's the case, you **should** return `None`
/// if `raw.len() > 1`.
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Self>;
}
/// A trait for any object that will represent a header field and value.
///
/// This trait represents the formatting of a `Header` for output to a TcpStream.
pub trait HeaderFormat: fmt::Debug + HeaderClone + Any + Typeable + Send + Sync {
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Self> where Self: Sized;
/// Format a header to be output into a TcpStream.
///
/// This method is not allowed to introduce an Err not produced
/// by the passed-in Formatter.
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result;
}
#[doc(hidden)]
pub trait HeaderClone {
fn clone_box(&self) -> Box<HeaderFormat + Send + Sync>;
fn clone_box(&self) -> Box<Header + Send + Sync>;
}
impl<T: HeaderFormat + Clone> HeaderClone for T {
impl<T: Header + Clone> HeaderClone for T {
#[inline]
fn clone_box(&self) -> Box<HeaderFormat + Send + Sync> {
fn clone_box(&self) -> Box<Header + Send + Sync> {
Box::new(self.clone())
}
}
impl HeaderFormat + Send + Sync {
impl Header + Send + Sync {
#[inline]
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
mem::transmute(traitobject::data(self))
@@ -165,9 +154,9 @@ impl HeaderFormat + Send + Sync {
}
}
impl Clone for Box<HeaderFormat + Send + Sync> {
impl Clone for Box<Header + Send + Sync> {
#[inline]
fn clone(&self) -> Box<HeaderFormat + Send + Sync> {
fn clone(&self) -> Box<Header + Send + Sync> {
self.clone_box()
}
}
@@ -183,6 +172,12 @@ pub struct Headers {
data: HashMap<HeaderName, Item>
}
impl Default for Headers {
fn default() -> Headers {
Headers::new()
}
}
impl Headers {
/// Creates a new, empty headers map.
@@ -212,8 +207,8 @@ impl Headers {
/// Set a header field to the corresponding value.
///
/// The field is determined by the type of the value being set.
pub fn set<H: Header + HeaderFormat>(&mut self, value: H) {
trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), value);
pub fn set<H: Header>(&mut self, value: H) {
trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), HeaderFormatter(&value));
self.data.insert(UniCase(CowStr(Cow::Borrowed(header_name::<H>()))),
Item::new_typed(Box::new(value)));
}
@@ -259,13 +254,13 @@ impl Headers {
}
/// Get a reference to the header field's value, if it exists.
pub fn get<H: Header + HeaderFormat>(&self) -> Option<&H> {
pub fn get<H: Header>(&self) -> Option<&H> {
self.data.get(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
.and_then(Item::typed::<H>)
}
/// Get a mutable reference to the header field's value, if it exists.
pub fn get_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> {
pub fn get_mut<H: Header>(&mut self) -> Option<&mut H> {
self.data.get_mut(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
.and_then(Item::typed_mut::<H>)
}
@@ -280,13 +275,13 @@ impl Headers {
/// # let mut headers = Headers::new();
/// let has_type = headers.has::<ContentType>();
/// ```
pub fn has<H: Header + HeaderFormat>(&self) -> bool {
pub fn has<H: Header>(&self) -> bool {
self.data.contains_key(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
}
/// Removes a header from the map, if one existed.
/// Returns true if a header has been removed.
pub fn remove<H: Header + HeaderFormat>(&mut self) -> bool {
pub fn remove<H: Header>(&mut self) -> bool {
trace!("Headers.remove( {:?} )", header_name::<H>());
self.data.remove(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))).is_some()
}
@@ -380,6 +375,7 @@ impl Deserialize for Headers {
}
/// An `Iterator` over the fields in a `Headers` map.
#[allow(missing_debug_implementations)]
pub struct HeadersItems<'a> {
inner: Iter<'a, HeaderName, Item>
}
@@ -410,7 +406,7 @@ impl<'a> HeaderView<'a> {
/// Cast the value to a certain Header type.
#[inline]
pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> {
pub fn value<H: Header>(&self) -> Option<&'a H> {
self.1.typed::<H>()
}
@@ -449,7 +445,7 @@ impl<'a> FromIterator<HeaderView<'a>> for Headers {
}
}
impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) {
impl<'a> fmt::Display for &'a (Header + Send + Sync) {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt_header(f)
@@ -461,16 +457,16 @@ impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) {
/// This can be used like so: `format!("{}", HeaderFormatter(&header))` to
/// get the representation of a Header which will be written to an
/// outgoing `TcpStream`.
pub struct HeaderFormatter<'a, H: HeaderFormat>(pub &'a H);
pub struct HeaderFormatter<'a, H: Header>(pub &'a H);
impl<'a, H: HeaderFormat> fmt::Display for HeaderFormatter<'a, H> {
impl<'a, H: Header> fmt::Display for HeaderFormatter<'a, H> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt_header(f)
}
}
impl<'a, H: HeaderFormat> fmt::Debug for HeaderFormatter<'a, H> {
impl<'a, H: Header> fmt::Debug for HeaderFormatter<'a, H> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt_header(f)
@@ -519,7 +515,7 @@ mod tests {
use mime::Mime;
use mime::TopLevel::Text;
use mime::SubLevel::Plain;
use super::{Headers, Header, HeaderFormat, ContentLength, ContentType,
use super::{Headers, Header, ContentLength, ContentType,
Accept, Host, qitem};
use httparse;
@@ -597,9 +593,7 @@ mod tests {
None => Err(::Error::Header),
}
}
}
impl HeaderFormat for CrazyLength {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
let CrazyLength(ref opt, ref value) = *self;
write!(f, "{:?}, {:?}", opt, value)

View File

@@ -137,6 +137,12 @@ define_encode_set! {
}
}
impl fmt::Debug for HTTP_VALUE {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("HTTP_VALUE")
}
}
impl Display for ExtendedValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let encoded_value =