use std::borrow::{Cow, ToOwned};
#[cfg(feature = "compat")]
use std::convert::From;
use std::iter::{FromIterator, IntoIterator};
use std::{mem, fmt};
#[cfg(feature = "compat")]
use http;
use unicase::Ascii;
use self::internals::{Item, VecMap, Entry};
use self::sealed::HeaderClone;
pub use self::shared::*;
pub use self::common::*;
pub use self::raw::Raw;
use bytes::Bytes;
mod common;
mod internals;
mod raw;
mod shared;
pub mod parsing;
pub trait Header: 'static + HeaderClone + Send + Sync {
fn header_name() -> &'static str where Self: Sized;
fn parse_header(raw: &Raw) -> ::Result<Self> where Self: Sized;
#[inline]
fn fmt_header(&self, f: &mut Formatter) -> fmt::Result;
}
mod sealed {
use super::Header;
#[doc(hidden)]
pub trait HeaderClone {
fn clone_box(&self) -> Box<Header + Send + Sync>;
}
impl<T: Header + Clone> HeaderClone for T {
#[inline]
fn clone_box(&self) -> Box<Header + Send + Sync> {
Box::new(self.clone())
}
}
}
#[allow(missing_debug_implementations)]
pub struct Formatter<'a, 'b: 'a>(Multi<'a, 'b>);
enum Multi<'a, 'b: 'a> {
Line(&'a str, &'a mut fmt::Formatter<'b>),
Join(bool, &'a mut fmt::Formatter<'b>),
Raw(&'a mut Raw),
}
impl<'a, 'b> Formatter<'a, 'b> {
pub fn fmt_line(&mut self, line: &fmt::Display) -> fmt::Result {
use std::fmt::Write;
match self.0 {
Multi::Line(name, ref mut f) => {
try!(f.write_str(name));
try!(f.write_str(": "));
try!(write!(NewlineReplacer(*f), "{}", line));
f.write_str("\r\n")
},
Multi::Join(ref mut first, ref mut f) => {
if !*first {
try!(f.write_str(", "));
} else {
*first = false;
}
write!(NewlineReplacer(*f), "{}", line)
}
Multi::Raw(ref mut raw) => {
let mut s = String::new();
try!(write!(NewlineReplacer(&mut s), "{}", line));
raw.push(s);
Ok(())
}
}
}
fn danger_fmt_line_without_newline_replacer<T: fmt::Display>(&mut self, line: &T) -> fmt::Result {
use std::fmt::Write;
match self.0 {
Multi::Line(name, ref mut f) => {
try!(f.write_str(name));
try!(f.write_str(": "));
try!(fmt::Display::fmt(line, f));
f.write_str("\r\n")
},
Multi::Join(ref mut first, ref mut f) => {
if !*first {
try!(f.write_str(", "));
} else {
*first = false;
}
fmt::Display::fmt(line, f)
}
Multi::Raw(ref mut raw) => {
let mut s = String::new();
try!(write!(s, "{}", line));
raw.push(s);
Ok(())
}
}
}
}
struct ValueString<'a>(&'a Item);
impl<'a> fmt::Debug for ValueString<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(f.write_str("\""));
try!(self.0.write_h1(&mut Formatter(Multi::Join(true, f))));
f.write_str("\"")
}
}
impl<'a> fmt::Display for ValueString<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.write_h1(&mut Formatter(Multi::Join(true, f)))
}
}
struct NewlineReplacer<'a, F: fmt::Write + 'a>(&'a mut F);
impl<'a, F: fmt::Write + 'a> fmt::Write for NewlineReplacer<'a, F> {
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
let mut since = 0;
for (i, &byte) in s.as_bytes().iter().enumerate() {
if byte == b'\r' || byte == b'\n' {
try!(self.0.write_str(&s[since..i]));
try!(self.0.write_str(" "));
since = i + 1;
}
}
if since < s.len() {
self.0.write_str(&s[since..])
} else {
Ok(())
}
}
#[inline]
fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
fmt::write(self, args)
}
}
impl Header + Send + Sync {
#[inline]
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
&*(mem::transmute::<*const _, (*const (), *const ())>(self).0 as *const T)
}
#[inline]
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
&mut *(mem::transmute::<*mut _, (*mut (), *mut ())>(self).0 as *mut T)
}
#[inline]
unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> T {
*Box::from_raw(mem::transmute::<*mut _, (*mut (), *mut ())>(Box::into_raw(self)).0 as *mut T)
}
}
impl Clone for Box<Header + Send + Sync> {
#[inline]
fn clone(&self) -> Box<Header + Send + Sync> {
self.clone_box()
}
}
#[inline]
fn header_name<T: Header>() -> &'static str {
<T as Header>::header_name()
}
#[derive(Clone)]
pub struct Headers {
data: VecMap<HeaderName, Item>,
}
impl Default for Headers {
fn default() -> Headers {
Headers::new()
}
}
macro_rules! literals {
($($len:expr => $($header:path),+;)+) => (
fn maybe_literal(s: &str) -> Cow<'static, str> {
match s.len() {
$($len => {
$(
if Ascii::new(<$header>::header_name()) == Ascii::new(s) {
return Cow::Borrowed(<$header>::header_name());
}
)+
})+
_ => ()
}
trace!("maybe_literal not found, copying {:?}", s);
Cow::Owned(s.to_owned())
}
#[test]
fn test_literal_lens() {
$(
$({
let s = <$header>::header_name();
assert!(s.len() == $len, "{:?} has len of {}, listed as {}", s, s.len(), $len);
})+
)+
}
);
}
literals! {
4 => Host, Date, ETag;
5 => Allow, Range;
6 => Accept, Cookie, Server, Expect;
7 => Upgrade, Referer, Expires;
8 => Location, IfMatch, IfRange;
10 => UserAgent, Connection, SetCookie;
12 => ContentType;
13 => Authorization<String>, CacheControl, LastModified, IfNoneMatch, AcceptRanges, ContentRange;
14 => ContentLength, AcceptCharset;
15 => AcceptEncoding, AcceptLanguage;
17 => TransferEncoding;
25 => StrictTransportSecurity;
27 => AccessControlAllowOrigin;
}
impl Headers {
#[inline]
pub fn new() -> Headers {
Headers::with_capacity(0)
}
#[inline]
pub fn with_capacity(len: usize) -> Headers {
Headers {
data: VecMap::with_capacity(len)
}
}
pub fn set<H: Header>(&mut self, value: H) {
self.data.insert(HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))),
Item::new_typed(value));
}
#[doc(hidden)]
pub fn __internal_set_pos<H: Header>(&mut self, pos: usize, value: H) {
self.data.insert_pos(
HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))),
Item::new_typed(value),
pos,
);
}
pub fn get<H: Header>(&self) -> Option<&H> {
self.data.get(&HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))))
.and_then(Item::typed::<H>)
}
pub fn get_mut<H: Header>(&mut self) -> Option<&mut H> {
self.data.get_mut(&HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))))
.and_then(Item::typed_mut::<H>)
}
pub fn has<H: Header>(&self) -> bool {
self.data.contains_key(&HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))))
}
pub fn remove<H: Header>(&mut self) -> Option<H> {
self.data.remove(&HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))))
.and_then(Item::into_typed::<H>)
}
pub fn iter(&self) -> HeadersItems {
HeadersItems {
inner: self.data.iter()
}
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn clear(&mut self) {
self.data.clear()
}
pub fn get_raw(&self, name: &str) -> Option<&Raw> {
self.data
.get(name)
.map(Item::raw)
}
pub fn set_raw<K: Into<Cow<'static, str>>, V: Into<Raw>>(&mut self, name: K, value: V) {
let name = name.into();
let value = value.into();
self.data.insert(HeaderName(Ascii::new(name)), Item::new_raw(value));
}
pub fn append_raw<K: Into<Cow<'static, str>>, V: Into<Raw>>(&mut self, name: K, value: V) {
let name = name.into();
let value = value.into();
let name = HeaderName(Ascii::new(name));
if let Some(item) = self.data.get_mut(&name) {
item.raw_mut().push(value);
return;
}
self.data.insert(name, Item::new_raw(value));
}
pub fn remove_raw(&mut self, name: &str) {
self.data.remove(name);
}
}
impl PartialEq for Headers {
fn eq(&self, other: &Headers) -> bool {
if self.len() != other.len() {
return false;
}
for header in self.iter() {
match other.get_raw(header.name()) {
Some(val) if val == self.get_raw(header.name()).unwrap() => {},
_ => { return false; }
}
}
true
}
}
impl fmt::Display for Headers {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for header in self.iter() {
try!(fmt::Display::fmt(&header, f));
}
Ok(())
}
}
impl fmt::Debug for Headers {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_map()
.entries(self.iter().map(|view| (view.0.as_ref(), ValueString(view.1))))
.finish()
}
}
#[cfg(feature = "compat")]
impl From<http::HeaderMap> for Headers {
fn from(mut header_map: http::HeaderMap) -> Headers {
let mut headers = Headers::new();
for (name, mut value_drain) in header_map.drain() {
if let Some(first_value) = value_drain.next() {
let mut raw: Raw = first_value.as_bytes().into();
for value in value_drain {
raw.push(value.as_bytes());
}
headers.append_raw(name.as_str().to_string(), raw);
}
}
headers
}
}
#[cfg(feature = "compat")]
impl From<Headers> for http::HeaderMap {
fn from(headers: Headers) -> http::HeaderMap {
let mut header_map = http::HeaderMap::new();
for header in headers.iter() {
let entry = header_map.entry(header.name())
.expect("attempted to convert invalid header name");
let mut value_iter = header.raw().iter().map(|line| {
http::header::HeaderValue::from_bytes(line)
.expect("attempted to convert invalid header value")
});
match entry {
http::header::Entry::Occupied(mut occupied) => {
for value in value_iter {
occupied.append(value);
}
},
http::header::Entry::Vacant(vacant) => {
if let Some(first_value) = value_iter.next() {
let mut occupied = vacant.insert_entry(first_value);
for value in value_iter {
occupied.append(value);
}
}
}
}
}
header_map
}
}
#[allow(missing_debug_implementations)]
pub struct HeadersItems<'a> {
inner: ::std::slice::Iter<'a, (HeaderName, Item)>
}
impl<'a> Iterator for HeadersItems<'a> {
type Item = HeaderView<'a>;
fn next(&mut self) -> Option<HeaderView<'a>> {
self.inner.next().map(|&(ref k, ref v)| HeaderView(k, v))
}
}
pub struct HeaderView<'a>(&'a HeaderName, &'a Item);
impl<'a> HeaderView<'a> {
#[inline]
pub fn is<H: Header>(&self) -> bool {
HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))) == *self.0
}
#[inline]
pub fn name(&self) -> &'a str {
self.0.as_ref()
}
#[inline]
pub fn value<H: Header>(&self) -> Option<&'a H> {
self.1.typed::<H>()
}
#[inline]
pub fn value_string(&self) -> String {
ValueString(self.1).to_string()
}
#[inline]
pub fn raw(&self) -> &Raw {
self.1.raw()
}
}
impl<'a> fmt::Display for HeaderView<'a> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.1.write_h1(&mut Formatter(Multi::Line(self.0.as_ref(), f)))
}
}
impl<'a> fmt::Debug for HeaderView<'a> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl<'a> Extend<HeaderView<'a>> for Headers {
fn extend<I: IntoIterator<Item=HeaderView<'a>>>(&mut self, iter: I) {
for header in iter {
self.data.insert((*header.0).clone(), (*header.1).clone());
}
}
}
impl<'a> Extend<(&'a str, Bytes)> for Headers {
fn extend<I: IntoIterator<Item=(&'a str, Bytes)>>(&mut self, iter: I) {
for (name, value) in iter {
let name = HeaderName(Ascii::new(maybe_literal(name)));
match self.data.entry(name) {
Entry::Vacant(entry) => {
entry.insert(Item::new_raw(self::raw::parsed(value)));
}
Entry::Occupied(entry) => {
self::raw::push(entry.into_mut().raw_mut(), value);
}
};
}
}
}
impl<'a> FromIterator<HeaderView<'a>> for Headers {
fn from_iter<I: IntoIterator<Item=HeaderView<'a>>>(iter: I) -> Headers {
let mut headers = Headers::new();
headers.extend(iter);
headers
}
}
#[derive(Clone, Debug)]
struct HeaderName(Ascii<Cow<'static, str>>);
impl fmt::Display for HeaderName {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self.0.as_ref(), f)
}
}
impl AsRef<str> for HeaderName {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl PartialEq for HeaderName {
#[inline]
fn eq(&self, other: &HeaderName) -> bool {
let s = self.as_ref();
let k = other.as_ref();
if s.as_ptr() == k.as_ptr() && s.len() == k.len() {
true
} else {
self.0 == other.0
}
}
}
impl PartialEq<HeaderName> for str {
fn eq(&self, other: &HeaderName) -> bool {
let k = other.as_ref();
if self.as_ptr() == k.as_ptr() && self.len() == k.len() {
true
} else {
other.0 == self
}
}
}
#[cfg(test)]
mod tests {
use std::fmt;
use super::{Headers, Header, Raw, ContentLength, ContentType, Host, SetCookie};
#[cfg(feature = "nightly")]
use test::Bencher;
macro_rules! make_header {
($name:expr, $value:expr) => ({
let mut headers = Headers::new();
headers.set_raw(String::from_utf8($name.to_vec()).unwrap(), $value.to_vec());
headers
});
($text:expr) => ({
let bytes = $text;
let colon = bytes.iter().position(|&x| x == b':').unwrap();
make_header!(&bytes[..colon], &bytes[colon + 2..])
})
}
#[test]
fn test_from_raw() {
let headers = make_header!(b"Content-Length", b"10");
assert_eq!(headers.get(), Some(&ContentLength(10)));
}
#[derive(Clone, PartialEq, Debug)]
struct CrazyLength(Option<bool>, usize);
impl Header for CrazyLength {
fn header_name() -> &'static str {
"content-length"
}
fn parse_header(raw: &Raw) -> ::Result<CrazyLength> {
use std::str::from_utf8;
use std::str::FromStr;
if let Some(line) = raw.one() {
let s = try!(from_utf8(line).map(|s| FromStr::from_str(s).map_err(|_| ::Error::Header)));
s.map(|u| CrazyLength(Some(false), u))
} else {
Err(::Error::Header)
}
}
fn fmt_header(&self, f: &mut super::Formatter) -> fmt::Result {
f.fmt_line(self)
}
}
impl fmt::Display for CrazyLength {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let CrazyLength(ref opt, ref value) = *self;
write!(f, "{:?}, {:?}", opt, value)
}
}
#[test]
fn test_different_structs_for_same_header() {
let headers = make_header!(b"Content-Length: 10");
assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
assert_eq!(headers.get::<CrazyLength>(), Some(&CrazyLength(Some(false), 10)));
}
#[test]
fn test_trailing_whitespace() {
let headers = make_header!(b"Content-Length: 10 ");
assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
}
#[test]
fn test_multiple_reads() {
let headers = make_header!(b"Content-Length: 10");
let ContentLength(one) = *headers.get::<ContentLength>().unwrap();
let ContentLength(two) = *headers.get::<ContentLength>().unwrap();
assert_eq!(one, two);
}
#[test]
fn test_different_reads() {
let mut headers = Headers::new();
headers.set_raw("Content-Length", "10");
headers.set_raw("Content-Type", "text/plain");
let ContentLength(_) = *headers.get::<ContentLength>().unwrap();
let ContentType(_) = *headers.get::<ContentType>().unwrap();
}
#[test]
fn test_typed_get_raw() {
let mut headers = Headers::new();
headers.set(ContentLength(15));
assert_eq!(headers.get_raw("content-length").unwrap(), "15");
headers.set(SetCookie(vec![
"foo=bar".to_string(),
"baz=quux; Path=/path".to_string()
]));
assert_eq!(headers.get_raw("set-cookie").unwrap(), &["foo=bar", "baz=quux; Path=/path"][..]);
}
#[test]
fn test_get_mutable() {
let mut headers = make_header!(b"Content-Length: 10");
*headers.get_mut::<ContentLength>().unwrap() = ContentLength(20);
assert_eq!(headers.get_raw("content-length").unwrap(), &[b"20".to_vec()][..]);
assert_eq!(*headers.get::<ContentLength>().unwrap(), ContentLength(20));
}
#[test]
fn test_headers_to_string() {
let mut headers = Headers::new();
headers.set(ContentLength(15));
headers.set(Host::new("foo.bar", None));
let s = headers.to_string();
assert!(s.contains("Host: foo.bar\r\n"));
assert!(s.contains("Content-Length: 15\r\n"));
}
#[test]
fn test_headers_to_string_raw() {
let mut headers = make_header!(b"Content-Length: 10");
headers.set_raw("x-foo", vec![b"foo".to_vec(), b"bar".to_vec()]);
let s = headers.to_string();
assert_eq!(s, "Content-Length: 10\r\nx-foo: foo\r\nx-foo: bar\r\n");
}
#[test]
fn test_set_raw() {
let mut headers = Headers::new();
headers.set(ContentLength(10));
headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"20".to_vec()][..]);
assert_eq!(headers.get(), Some(&ContentLength(20)));
}
#[test]
fn test_append_raw() {
let mut headers = Headers::new();
headers.set(ContentLength(10));
headers.append_raw("content-LENGTH", b"20".to_vec());
assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"10".to_vec(), b"20".to_vec()][..]);
headers.append_raw("x-foo", "bar");
assert_eq!(headers.get_raw("x-foo").unwrap(), &[b"bar".to_vec()][..]);
}
#[test]
fn test_remove_raw() {
let mut headers = Headers::new();
headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
headers.remove_raw("content-LENGTH");
assert_eq!(headers.get_raw("Content-length"), None);
}
#[test]
fn test_remove() {
let mut headers = Headers::new();
headers.set(ContentLength(10));
assert_eq!(headers.remove(), Some(ContentLength(10)));
assert_eq!(headers.len(), 0);
headers.set(ContentLength(9));
assert_eq!(headers.len(), 1);
assert!(headers.remove::<CrazyLength>().is_none());
assert_eq!(headers.len(), 0);
}
#[test]
fn test_len() {
let mut headers = Headers::new();
headers.set(ContentLength(10));
assert_eq!(headers.len(), 1);
headers.set(ContentType::json());
assert_eq!(headers.len(), 2);
headers.set(ContentLength(20));
assert_eq!(headers.len(), 2);
}
#[test]
fn test_clear() {
let mut headers = Headers::new();
headers.set(ContentLength(10));
headers.set(ContentType::json());
assert_eq!(headers.len(), 2);
headers.clear();
assert_eq!(headers.len(), 0);
}
#[test]
fn test_iter() {
let mut headers = Headers::new();
headers.set(ContentLength(11));
for header in headers.iter() {
assert!(header.is::<ContentLength>());
assert_eq!(header.name(), <ContentLength as Header>::header_name());
assert_eq!(header.value(), Some(&ContentLength(11)));
assert_eq!(header.value_string(), "11".to_owned());
}
}
#[test]
fn test_header_view_value_string() {
let mut headers = Headers::new();
headers.set_raw("foo", vec![b"one".to_vec(), b"two".to_vec()]);
for header in headers.iter() {
assert_eq!(header.name(), "foo");
assert_eq!(header.value_string(), "one, two");
}
}
#[test]
fn test_header_view_raw() {
let mut headers = Headers::new();
headers.set_raw("foo", vec![b"one".to_vec(), b"two".to_vec()]);
for header in headers.iter() {
assert_eq!(header.name(), "foo");
let values: Vec<&[u8]> = header.raw().iter().collect();
assert_eq!(values, vec![b"one", b"two"]);
}
}
#[test]
fn test_eq() {
let mut headers1 = Headers::new();
let mut headers2 = Headers::new();
assert_eq!(headers1, headers2);
headers1.set(ContentLength(11));
headers2.set(Host::new("foo.bar", None));
assert_ne!(headers1, headers2);
headers1 = Headers::new();
headers2 = Headers::new();
headers1.set(ContentLength(11));
headers2.set(ContentLength(11));
assert_eq!(headers1, headers2);
headers1.set(ContentLength(10));
assert_ne!(headers1, headers2);
headers1 = Headers::new();
headers2 = Headers::new();
headers1.set(Host::new("foo.bar", None));
headers1.set(ContentLength(11));
headers2.set(ContentLength(11));
assert_ne!(headers1, headers2);
}
#[test]
#[cfg(feature = "compat")]
fn test_compat() {
use http;
let mut orig_hyper_headers = Headers::new();
orig_hyper_headers.set(ContentLength(11));
orig_hyper_headers.set(Host::new("foo.bar", None));
orig_hyper_headers.append_raw("x-foo", b"bar".to_vec());
orig_hyper_headers.append_raw("x-foo", b"quux".to_vec());
let mut orig_http_headers = http::HeaderMap::new();
orig_http_headers.insert(http::header::CONTENT_LENGTH, "11".parse().unwrap());
orig_http_headers.insert(http::header::HOST, "foo.bar".parse().unwrap());
orig_http_headers.append("x-foo", "bar".parse().unwrap());
orig_http_headers.append("x-foo", "quux".parse().unwrap());
let conv_hyper_headers: Headers = orig_http_headers.clone().into();
let conv_http_headers: http::HeaderMap = orig_hyper_headers.clone().into();
assert_eq!(orig_hyper_headers, conv_hyper_headers);
assert_eq!(orig_http_headers, conv_http_headers);
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_new(b: &mut Bencher) {
b.iter(|| {
let mut h = Headers::new();
h.set(ContentLength(11));
h
})
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_get(b: &mut Bencher) {
let mut headers = Headers::new();
headers.set(ContentLength(11));
b.iter(|| assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(11))))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_get_miss(b: &mut Bencher) {
let headers = Headers::new();
b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_get_miss_previous_10(b: &mut Bencher) {
let mut headers = Headers::new();
for i in 0..10 {
headers.set_raw(format!("non-standard-{}", i), "hi");
}
b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_set(b: &mut Bencher) {
let mut headers = Headers::new();
b.iter(|| headers.set(ContentLength(12)))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_set_previous_10(b: &mut Bencher) {
let mut headers = Headers::new();
for i in 0..10 {
headers.set_raw(format!("non-standard-{}", i), "hi");
}
b.iter(|| headers.set(ContentLength(12)))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_set_raw(b: &mut Bencher) {
let mut headers = Headers::new();
b.iter(|| headers.set_raw("non-standard", "hello"))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_set_raw_previous_10(b: &mut Bencher) {
let mut headers = Headers::new();
for i in 0..10 {
headers.set_raw(format!("non-standard-{}", i), "hi");
}
b.iter(|| headers.set_raw("non-standard", "hello"))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_has(b: &mut Bencher) {
let mut headers = Headers::new();
headers.set(ContentLength(11));
b.iter(|| assert!(headers.has::<ContentLength>()))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_view_is(b: &mut Bencher) {
let mut headers = Headers::new();
headers.set(ContentLength(11));
let mut iter = headers.iter();
let view = iter.next().unwrap();
b.iter(|| assert!(view.is::<ContentLength>()))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_fmt(b: &mut Bencher) {
use std::fmt::Write;
let mut buf = String::with_capacity(64);
let mut headers = Headers::new();
headers.set(ContentLength(11));
headers.set(ContentType::json());
b.bytes = headers.to_string().len() as u64;
b.iter(|| {
let _ = write!(buf, "{}", headers);
::test::black_box(&buf);
unsafe { buf.as_mut_vec().set_len(0); }
})
}
}