1use std::any::Any;
82use std::borrow::{Cow, ToOwned};
83use std::iter::{FromIterator, IntoIterator};
86use std::ops::{Deref, DerefMut};
87use std::{mem, fmt};
88
89use {httparse, traitobject};
90use typeable::Typeable;
91use unicase::UniCase;
92
93use self::internals::{Item, VecMap, Entry};
94use self::sealed::Sealed;
95
96pub use self::shared::*;
97pub use self::common::*;
98
99mod common;
100mod internals;
101mod shared;
102pub mod parsing;
103
104type HeaderName = UniCase<CowStr>;
105
106pub trait Header: Clone + Any + Send + Sync {
111 fn header_name() -> &'static str;
115 fn parse_header(raw: &[Vec<u8>]) -> crate::Result<Self>;
123
124}
125
126pub trait HeaderFormat: fmt::Debug + HeaderClone + Any + Typeable + Send + Sync {
130 fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result;
135
136 #[doc(hidden)]
145 #[inline]
146 fn fmt_multi_header(&self, f: &mut MultilineFormatter) -> fmt::Result {
147 f.fmt_line(&FmtHeader(self))
148 }
149}
150
151#[doc(hidden)]
152#[allow(missing_debug_implementations)]
153pub struct MultilineFormatter<'a, 'b: 'a>(Multi<'a, 'b>);
154
155enum Multi<'a, 'b: 'a> {
156 Line(&'a str, &'a mut fmt::Formatter<'b>),
157 Join(bool, &'a mut fmt::Formatter<'b>),
158}
159
160impl<'a, 'b> MultilineFormatter<'a, 'b> {
161 fn fmt_line(&mut self, line: &dyn fmt::Display) -> fmt::Result {
162 use std::fmt::Write;
163 match self.0 {
164 Multi::Line(ref name, ref mut f) => {
165 r#try!(f.write_str(*name));
166 r#try!(f.write_str(": "));
167 r#try!(write!(NewlineReplacer(*f), "{}", line));
168 f.write_str("\r\n")
169 },
170 Multi::Join(ref mut first, ref mut f) => {
171 if !*first {
172 r#try!(f.write_str(", "));
173 } else {
174 *first = false;
175 }
176 write!(NewlineReplacer(*f), "{}", line)
177 }
178 }
179 }
180}
181
182struct FmtHeader<'a, H: ?Sized + 'a>(&'a H);
184
185impl<'a, H: HeaderFormat + ?Sized + 'a> fmt::Display for FmtHeader<'a, H> {
186 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187 self.0.fmt_header(f)
188 }
189}
190
191struct ValueString<'a>(&'a Item);
192
193impl<'a> fmt::Display for ValueString<'a> {
194 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
195 self.0.write_h1(&mut MultilineFormatter(Multi::Join(true, f)))
196 }
197}
198
199struct NewlineReplacer<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>);
200
201impl<'a, 'b> fmt::Write for NewlineReplacer<'a, 'b> {
202 fn write_str(&mut self, s: &str) -> fmt::Result {
203 let mut since = 0;
204 for (i, &byte) in s.as_bytes().iter().enumerate() {
205 if byte == b'\r' || byte == b'\n' {
206 r#try!(self.0.write_str(&s[since..i]));
207 r#try!(self.0.write_str(" "));
208 since = i + 1;
209 }
210 }
211 if since < s.len() {
212 self.0.write_str(&s[since..])
213 } else {
214 Ok(())
215 }
216 }
217}
218
219pub trait HeaderClone: Sealed {}
225impl<T: Sealed> HeaderClone for T {}
226
227mod sealed {
228 use super::HeaderFormat;
229
230 #[doc(hidden)]
231 pub trait Sealed {
232 #[doc(hidden)]
233 fn clone_box(&self) -> Box<dyn HeaderFormat + Send + Sync>;
234 }
235
236 #[doc(hidden)]
237 impl<T: HeaderFormat + Clone> Sealed for T {
238 #[inline]
239 fn clone_box(&self) -> Box<dyn HeaderFormat + Send + Sync> {
240 Box::new(self.clone())
241 }
242 }
243}
244
245impl dyn HeaderFormat + Send + Sync {
246 #[inline]
247 unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
248 mem::transmute(traitobject::data(self))
249 }
250
251 #[inline]
252 unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
253 mem::transmute(traitobject::data_mut(self))
254 }
255}
256
257impl Clone for Box<dyn HeaderFormat + Send + Sync> {
258 #[inline]
259 fn clone(&self) -> Box<dyn HeaderFormat + Send + Sync> {
260 self.clone_box()
261 }
262}
263
264#[inline]
265fn header_name<T: Header>() -> &'static str {
266 <T as Header>::header_name()
267}
268
269#[derive(Clone)]
271pub struct Headers {
272 data: VecMap<HeaderName, Item>,
274}
275
276impl Headers {
277
278 pub fn new() -> Headers {
280 Headers {
281 data: VecMap::new()
282 }
283 }
284
285 pub fn with_capacity(capacity: usize) -> Headers {
286 Headers {
287 data: VecMap::with_capacity(capacity)
288 }
289 }
290
291 pub fn from_raw(raw: &[httparse::Header]) -> crate::Result<Headers> {
292 let mut headers = Headers::new();
293 for header in raw {
294 let name = UniCase(CowStr(Cow::Owned(header.name.to_owned())));
295 let item = match headers.data.entry(name) {
296 Entry::Vacant(entry) => entry.insert(Item::new_raw(vec![])),
297 Entry::Occupied(entry) => entry.into_mut()
298 };
299 item.raw_mut().push(header.value.to_vec());
300 }
301 Ok(headers)
302 }
303
304 pub fn set<H: Header + HeaderFormat>(&mut self, value: H) {
308 trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), value);
309 self.data.insert(UniCase(CowStr(Cow::Borrowed(header_name::<H>()))),
310 Item::new_typed(Box::new(value)));
311 }
312
313 pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> {
325 self.data
326 .get(&UniCase(CowStr(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))))
327 .map(Item::raw)
328 }
329
330 pub fn set_raw<K: Into<Cow<'static, str>>>(&mut self, name: K,
343 value: Vec<Vec<u8>>) {
344 let name = name.into();
345 trace!("Headers.set_raw( {:?}, {:?} )", name, value);
346 self.data.insert(UniCase(CowStr(name)), Item::new_raw(value));
347 }
348
349 pub fn append_raw<K: Into<Cow<'static, str>>>(&mut self, name: K, value: Vec<u8>) {
365 let name = name.into();
366 trace!("Headers.append_raw( {:?}, {:?} )", name, value);
367 let name = UniCase(CowStr(name));
368 if let Some(item) = self.data.get_mut(&name) {
369 item.raw_mut().push(value);
370 return;
371 }
372 self.data.insert(name, Item::new_raw(vec![value]));
373 }
374
375 pub fn remove_raw(&mut self, name: &str) {
377 trace!("Headers.remove_raw( {:?} )", name);
378 self.data.remove(
379 &UniCase(CowStr(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) })))
380 );
381 }
382
383 pub fn get<H: Header + HeaderFormat>(&self) -> Option<&H> {
385 self.data.get(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
386 .and_then(Item::typed::<H>)
387 }
388
389 pub fn get_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> {
391 self.data.get_mut(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
392 .and_then(Item::typed_mut::<H>)
393 }
394
395 pub fn has<H: Header + HeaderFormat>(&self) -> bool {
406 self.data.contains_key(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
407 }
408
409 pub fn remove<H: Header + HeaderFormat>(&mut self) -> bool {
412 trace!("Headers.remove( {:?} )", header_name::<H>());
413 self.data.remove(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))).is_some()
414 }
415
416 pub fn iter(&self) -> HeadersItems {
418 HeadersItems {
419 inner: self.data.iter()
420 }
421 }
422
423 pub fn len(&self) -> usize {
425 self.data.len()
426 }
427
428 pub fn clear(&mut self) {
430 self.data.clear()
431 }
432}
433
434impl PartialEq for Headers {
435 fn eq(&self, other: &Headers) -> bool {
436 if self.len() != other.len() {
437 return false;
438 }
439
440 for header in self.iter() {
441 match other.get_raw(header.name()) {
442 Some(val) if val == self.get_raw(header.name()).unwrap() => {},
443 _ => { return false; }
444 }
445 }
446 true
447 }
448}
449
450impl fmt::Display for Headers {
451 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
452 for header in self.iter() {
453 r#try!(fmt::Display::fmt(&header, f));
454 }
455 Ok(())
456 }
457}
458
459impl fmt::Debug for Headers {
460 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
461 r#try!(f.write_str("Headers { "));
462 for header in self.iter() {
463 r#try!(write!(f, "{:?}, ", header));
464 }
465 r#try!(f.write_str("}"));
466 Ok(())
467 }
468}
469
470pub struct HeadersItems<'a> {
472 inner: ::std::slice::Iter<'a, (HeaderName, Item)>
473}
474
475impl<'a> Iterator for HeadersItems<'a> {
476 type Item = HeaderView<'a>;
477
478 fn next(&mut self) -> Option<HeaderView<'a>> {
479 self.inner.next().map(|&(ref k, ref v)| HeaderView(k, v))
480 }
481}
482
483pub struct HeaderView<'a>(&'a HeaderName, &'a Item);
485
486impl<'a> HeaderView<'a> {
487 #[inline]
489 pub fn is<H: Header>(&self) -> bool {
490 UniCase(CowStr(Cow::Borrowed(header_name::<H>()))) == *self.0
491 }
492
493 #[inline]
495 pub fn name(&self) -> &'a str {
496 self.0.as_ref()
497 }
498
499 #[inline]
501 pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> {
502 self.1.typed::<H>()
503 }
504
505 #[inline]
512 pub fn value_string(&self) -> String {
513 ValueString(self.1).to_string()
514 }
515}
516
517impl<'a> fmt::Display for HeaderView<'a> {
518 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
519 self.1.write_h1(&mut MultilineFormatter(Multi::Line(&self.0, f)))
520 }
521}
522
523impl<'a> fmt::Debug for HeaderView<'a> {
524 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
525 fmt::Display::fmt(self, f)
526 }
527}
528
529impl<'a> Extend<HeaderView<'a>> for Headers {
530 fn extend<I: IntoIterator<Item=HeaderView<'a>>>(&mut self, iter: I) {
531 for header in iter {
532 self.data.insert((*header.0).clone(), (*header.1).clone());
533 }
534 }
535}
536
537impl<'a> FromIterator<HeaderView<'a>> for Headers {
538 fn from_iter<I: IntoIterator<Item=HeaderView<'a>>>(iter: I) -> Headers {
539 let mut headers = Headers::new();
540 headers.extend(iter);
541 headers
542 }
543}
544
545impl<'a> fmt::Display for &'a (dyn HeaderFormat + Send + Sync) {
547 #[inline]
548 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
549 let mut multi = MultilineFormatter(Multi::Join(true, f));
550 self.fmt_multi_header(&mut multi)
551 }
552}
553
554#[deprecated(note="The semantics of formatting a HeaderFormat directly are not clear")]
562pub struct HeaderFormatter<'a, H: HeaderFormat>(pub &'a H);
563
564#[allow(deprecated)]
565impl<'a, H: HeaderFormat> fmt::Display for HeaderFormatter<'a, H> {
566 #[inline]
567 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
568 let mut multi = MultilineFormatter(Multi::Join(true, f));
569 self.0.fmt_multi_header(&mut multi)
570 }
571}
572
573#[allow(deprecated)]
574impl<'a, H: HeaderFormat> fmt::Debug for HeaderFormatter<'a, H> {
575 #[inline]
576 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
577 fmt::Display::fmt(self, f)
578 }
579}
580
581#[derive(Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
582struct CowStr(Cow<'static, str>);
583
584impl Deref for CowStr {
585 type Target = Cow<'static, str>;
586
587 fn deref(&self) -> &Cow<'static, str> {
588 &self.0
589 }
590}
591
592impl fmt::Debug for CowStr {
593 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
594 fmt::Debug::fmt(&self.0, f)
595 }
596}
597
598impl fmt::Display for CowStr {
599 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
600 fmt::Display::fmt(&self.0, f)
601 }
602}
603
604impl DerefMut for CowStr {
605 fn deref_mut(&mut self) -> &mut Cow<'static, str> {
606 &mut self.0
607 }
608}
609
610impl AsRef<str> for CowStr {
611 fn as_ref(&self) -> &str {
612 self
613 }
614}
615
616
617#[cfg(test)]
618mod tests {
619 use std::fmt;
620 use mime::Mime;
621 use mime::TopLevel::Text;
622 use mime::SubLevel::Plain;
623 use super::{Headers, Header, HeaderFormat, ContentLength, ContentType,
624 Accept, Host, qitem};
625 use httparse;
626
627 #[cfg(feature = "nightly")]
628 use test::Bencher;
629
630 fn index_of(slice: &[u8], byte: u8) -> Option<usize> {
632 for (index, &b) in slice.iter().enumerate() {
633 if b == byte {
634 return Some(index);
635 }
636 }
637 None
638 }
639
640 macro_rules! raw {
641 ($($line:expr),*) => ({
642 [$({
643 let line = $line;
644 let pos = index_of(line, b':').expect("raw splits on ':', not found");
645 httparse::Header {
646 name: ::std::str::from_utf8(&line[..pos]).unwrap(),
647 value: &line[pos + 2..]
648 }
649 }),*]
650 })
651 }
652
653 #[test]
654 fn test_from_raw() {
655 let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
656 assert_eq!(headers.get(), Some(&ContentLength(10)));
657 }
658
659 #[test]
660 fn test_content_type() {
661 let content_type = Header::parse_header([b"text/plain".to_vec()].as_ref());
662 assert_eq!(content_type.ok(), Some(ContentType(Mime(Text, Plain, vec![]))));
663 }
664
665 #[test]
666 fn test_accept() {
667 let text_plain = qitem(Mime(Text, Plain, vec![]));
668 let application_vendor = "application/vnd.github.v3.full+json; q=0.5".parse().unwrap();
669
670 let accept = Header::parse_header([b"text/plain".to_vec()].as_ref());
671 assert_eq!(accept.ok(), Some(Accept(vec![text_plain.clone()])));
672
673 let bytevec = [b"application/vnd.github.v3.full+json; q=0.5, text/plain".to_vec()];
674 let accept = Header::parse_header(bytevec.as_ref());
675 assert_eq!(accept.ok(), Some(Accept(vec![application_vendor, text_plain])));
676 }
677
678 #[derive(Clone, PartialEq, Debug)]
679 struct CrazyLength(Option<bool>, usize);
680
681 impl Header for CrazyLength {
682 fn header_name() -> &'static str {
683 "content-length"
684 }
685 fn parse_header(raw: &[Vec<u8>]) -> crate::Result<CrazyLength> {
686 use std::str::from_utf8;
687 use std::str::FromStr;
688
689 if raw.len() != 1 {
690 return Err(crate::Error::Header);
691 }
692 match match from_utf8(unsafe { &raw.get_unchecked(0)[..] }) {
694 Ok(s) => FromStr::from_str(s).ok(),
695 Err(_) => None
696 }.map(|u| CrazyLength(Some(false), u)) {
697 Some(x) => Ok(x),
698 None => Err(crate::Error::Header),
699 }
700 }
701 }
702
703 impl HeaderFormat for CrazyLength {
704 fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
705 let CrazyLength(ref opt, ref value) = *self;
706 write!(f, "{:?}, {:?}", opt, value)
707 }
708 }
709
710 #[test]
711 fn test_different_structs_for_same_header() {
712 let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
713 assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
714 assert_eq!(headers.get::<CrazyLength>(), Some(&CrazyLength(Some(false), 10)));
715 }
716
717 #[test]
718 fn test_trailing_whitespace() {
719 let headers = Headers::from_raw(&raw!(b"Content-Length: 10 ")).unwrap();
720 assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
721 }
722
723 #[test]
724 fn test_multiple_reads() {
725 let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
726 let ContentLength(one) = *headers.get::<ContentLength>().unwrap();
727 let ContentLength(two) = *headers.get::<ContentLength>().unwrap();
728 assert_eq!(one, two);
729 }
730
731 #[test]
732 fn test_different_reads() {
733 let headers = Headers::from_raw(
734 &raw!(b"Content-Length: 10", b"Content-Type: text/plain")).unwrap();
735 let ContentLength(_) = *headers.get::<ContentLength>().unwrap();
736 let ContentType(_) = *headers.get::<ContentType>().unwrap();
737 }
738
739 #[test]
740 fn test_get_mutable() {
741 let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
742 *headers.get_mut::<ContentLength>().unwrap() = ContentLength(20);
743 assert_eq!(headers.get_raw("content-length").unwrap(), &[b"20".to_vec()][..]);
744 assert_eq!(*headers.get::<ContentLength>().unwrap(), ContentLength(20));
745 }
746
747 #[test]
748 fn test_headers_fmt() {
749 let mut headers = Headers::new();
750 headers.set(ContentLength(15));
751 headers.set(Host { hostname: "foo.bar".to_owned(), port: None });
752
753 let s = headers.to_string();
754 assert!(s.contains("Host: foo.bar\r\n"));
755 assert!(s.contains("Content-Length: 15\r\n"));
756 }
757
758 #[test]
759 fn test_headers_fmt_raw() {
760 let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
761 headers.set_raw("x-foo", vec![b"foo".to_vec(), b"bar".to_vec()]);
762 let s = headers.to_string();
763 assert_eq!(s, "Content-Length: 10\r\nx-foo: foo\r\nx-foo: bar\r\n");
764 }
765
766 #[test]
767 fn test_set_raw() {
768 let mut headers = Headers::new();
769 headers.set(ContentLength(10));
770 headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
771 assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"20".to_vec()][..]);
772 assert_eq!(headers.get(), Some(&ContentLength(20)));
773 }
774
775 #[test]
776 fn test_append_raw() {
777 let mut headers = Headers::new();
778 headers.set(ContentLength(10));
779 headers.append_raw("content-LENGTH", b"20".to_vec());
780 assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"10".to_vec(), b"20".to_vec()][..]);
781 headers.append_raw("x-foo", b"bar".to_vec());
782 assert_eq!(headers.get_raw("x-foo"), Some(&[b"bar".to_vec()][..]));
783 }
784
785 #[test]
786 fn test_remove_raw() {
787 let mut headers = Headers::new();
788 headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
789 headers.remove_raw("content-LENGTH");
790 assert_eq!(headers.get_raw("Content-length"), None);
791 }
792
793 #[test]
794 fn test_len() {
795 let mut headers = Headers::new();
796 headers.set(ContentLength(10));
797 assert_eq!(headers.len(), 1);
798 headers.set(ContentType(Mime(Text, Plain, vec![])));
799 assert_eq!(headers.len(), 2);
800 headers.set(ContentLength(20));
802 assert_eq!(headers.len(), 2);
803 }
804
805 #[test]
806 fn test_clear() {
807 let mut headers = Headers::new();
808 headers.set(ContentLength(10));
809 headers.set(ContentType(Mime(Text, Plain, vec![])));
810 assert_eq!(headers.len(), 2);
811 headers.clear();
812 assert_eq!(headers.len(), 0);
813 }
814
815 #[test]
816 fn test_iter() {
817 let mut headers = Headers::new();
818 headers.set(ContentLength(11));
819 for header in headers.iter() {
820 assert!(header.is::<ContentLength>());
821 assert_eq!(header.name(), <ContentLength as Header>::header_name());
822 assert_eq!(header.value(), Some(&ContentLength(11)));
823 assert_eq!(header.value_string(), "11".to_owned());
824 }
825 }
826
827 #[test]
828 fn test_header_view_value_string() {
829 let mut headers = Headers::new();
830 headers.set_raw("foo", vec![b"one".to_vec(), b"two".to_vec()]);
831 for header in headers.iter() {
832 assert_eq!(header.name(), "foo");
833 assert_eq!(header.value_string(), "one, two");
834 }
835 }
836
837 #[test]
838 fn test_eq() {
839 let mut headers1 = Headers::new();
840 let mut headers2 = Headers::new();
841
842 assert_eq!(headers1, headers2);
843
844 headers1.set(ContentLength(11));
845 headers2.set(Host {hostname: "foo.bar".to_owned(), port: None});
846 assert!(headers1 != headers2);
847
848 headers1 = Headers::new();
849 headers2 = Headers::new();
850
851 headers1.set(ContentLength(11));
852 headers2.set(ContentLength(11));
853 assert_eq!(headers1, headers2);
854
855 headers1.set(ContentLength(10));
856 assert!(headers1 != headers2);
857
858 headers1 = Headers::new();
859 headers2 = Headers::new();
860
861 headers1.set(Host { hostname: "foo.bar".to_owned(), port: None });
862 headers1.set(ContentLength(11));
863 headers2.set(ContentLength(11));
864 assert!(headers1 != headers2);
865 }
866
867 #[cfg(feature = "nightly")]
868 #[bench]
869 fn bench_headers_new(b: &mut Bencher) {
870 b.iter(|| {
871 let mut h = Headers::new();
872 h.set(ContentLength(11));
873 h
874 })
875 }
876
877 #[cfg(feature = "nightly")]
878 #[bench]
879 fn bench_headers_from_raw(b: &mut Bencher) {
880 let raw = raw!(b"Content-Length: 10");
881 b.iter(|| Headers::from_raw(&raw).unwrap())
882 }
883
884 #[cfg(feature = "nightly")]
885 #[bench]
886 fn bench_headers_get(b: &mut Bencher) {
887 let mut headers = Headers::new();
888 headers.set(ContentLength(11));
889 b.iter(|| assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(11))))
890 }
891
892 #[cfg(feature = "nightly")]
893 #[bench]
894 fn bench_headers_get_miss(b: &mut Bencher) {
895 let headers = Headers::new();
896 b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
897 }
898
899 #[cfg(feature = "nightly")]
900 #[bench]
901 fn bench_headers_set(b: &mut Bencher) {
902 let mut headers = Headers::new();
903 b.iter(|| headers.set(ContentLength(12)))
904 }
905
906 #[cfg(feature = "nightly")]
907 #[bench]
908 fn bench_headers_has(b: &mut Bencher) {
909 let mut headers = Headers::new();
910 headers.set(ContentLength(11));
911 b.iter(|| assert!(headers.has::<ContentLength>()))
912 }
913
914 #[cfg(feature = "nightly")]
915 #[bench]
916 fn bench_headers_view_is(b: &mut Bencher) {
917 let mut headers = Headers::new();
918 headers.set(ContentLength(11));
919 let mut iter = headers.iter();
920 let view = iter.next().unwrap();
921 b.iter(|| assert!(view.is::<ContentLength>()))
922 }
923
924 #[cfg(feature = "nightly")]
925 #[bench]
926 fn bench_headers_fmt(b: &mut Bencher) {
927 let mut headers = Headers::new();
928 headers.set(ContentLength(11));
929 b.iter(|| headers.to_string())
930 }
931}