Merge pull request #814 from hyperium/headers-vec-map
perf(headers): use a VecMap, and check name against literals
This commit is contained in:
		| @@ -42,7 +42,8 @@ const ACCESS_CONTROL_ALLOW_CREDENTIALS_TRUE: UniCase<&'static str> = UniCase("tr | |||||||
|  |  | ||||||
| impl Header for AccessControlAllowCredentials { | impl Header for AccessControlAllowCredentials { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Access-Control-Allow-Credentials" |         static NAME: &'static str = "Access-Control-Allow-Credentials"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<AccessControlAllowCredentials> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<AccessControlAllowCredentials> { | ||||||
|   | |||||||
| @@ -73,7 +73,8 @@ impl<S: Scheme> DerefMut for Authorization<S> { | |||||||
|  |  | ||||||
| impl<S: Scheme + Any> Header for Authorization<S> where <S as FromStr>::Err: 'static { | impl<S: Scheme + Any> Header for Authorization<S> where <S as FromStr>::Err: 'static { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Authorization" |         static NAME: &'static str = "Authorization"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Authorization<S>> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Authorization<S>> { | ||||||
|   | |||||||
| @@ -51,7 +51,8 @@ __hyper__deref!(CacheControl => Vec<CacheDirective>); | |||||||
|  |  | ||||||
| impl Header for CacheControl { | impl Header for CacheControl { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Cache-Control" |         static NAME: &'static str = "Cache-Control"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<CacheControl> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<CacheControl> { | ||||||
|   | |||||||
| @@ -90,7 +90,8 @@ pub struct ContentDisposition { | |||||||
|  |  | ||||||
| impl Header for ContentDisposition { | impl Header for ContentDisposition { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Content-Disposition" |         static NAME: &'static str = "Content-Disposition"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<ContentDisposition> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<ContentDisposition> { | ||||||
|   | |||||||
| @@ -32,10 +32,13 @@ use header::{Header, parsing}; | |||||||
| #[derive(Clone, Copy, Debug, PartialEq)] | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
| pub struct ContentLength(pub u64); | pub struct ContentLength(pub u64); | ||||||
|  |  | ||||||
|  | //static NAME: &'static str = "Content-Length"; | ||||||
|  |  | ||||||
| impl Header for ContentLength { | impl Header for ContentLength { | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Content-Length" |         static NAME: &'static str = "Content-Length"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<ContentLength> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<ContentLength> { | ||||||
|         // If multiple Content-Length headers were sent, everything can still |         // If multiple Content-Length headers were sent, everything can still | ||||||
|   | |||||||
| @@ -39,7 +39,8 @@ __hyper__deref!(Cookie => Vec<CookiePair>); | |||||||
|  |  | ||||||
| impl Header for Cookie { | impl Header for Cookie { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Cookie" |         static NAME: &'static str = "Cookie"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Cookie> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Cookie> { | ||||||
|   | |||||||
| @@ -30,7 +30,8 @@ const EXPECT_CONTINUE: UniCase<&'static str> = UniCase("100-continue"); | |||||||
|  |  | ||||||
| impl Header for Expect { | impl Header for Expect { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Expect" |         static NAME: &'static str = "Expect"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Expect> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Expect> { | ||||||
|   | |||||||
| @@ -43,7 +43,8 @@ pub struct Host { | |||||||
|  |  | ||||||
| impl Header for Host { | impl Header for Host { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Host" |         static NAME: &'static str = "Host"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Host> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Host> { | ||||||
|   | |||||||
| @@ -55,7 +55,8 @@ pub enum IfRange { | |||||||
|  |  | ||||||
| impl Header for IfRange { | impl Header for IfRange { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "If-Range" |         static NAME: &'static str = "If-Range"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<IfRange> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<IfRange> { | ||||||
|         let etag: ::Result<EntityTag> = header::parsing::from_one_raw_str(raw); |         let etag: ::Result<EntityTag> = header::parsing::from_one_raw_str(raw); | ||||||
|   | |||||||
| @@ -217,7 +217,8 @@ macro_rules! header { | |||||||
|         __hyper__deref!($id => Vec<$item>); |         __hyper__deref!($id => Vec<$item>); | ||||||
|         impl $crate::header::Header for $id { |         impl $crate::header::Header for $id { | ||||||
|             fn header_name() -> &'static str { |             fn header_name() -> &'static str { | ||||||
|                 $n |                 static NAME: &'static str = $n; | ||||||
|  |                 NAME | ||||||
|             } |             } | ||||||
|             fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> { |             fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> { | ||||||
|                 $crate::header::parsing::from_comma_delimited(raw).map($id) |                 $crate::header::parsing::from_comma_delimited(raw).map($id) | ||||||
| @@ -243,7 +244,8 @@ macro_rules! header { | |||||||
|         __hyper__deref!($id => Vec<$item>); |         __hyper__deref!($id => Vec<$item>); | ||||||
|         impl $crate::header::Header for $id { |         impl $crate::header::Header for $id { | ||||||
|             fn header_name() -> &'static str { |             fn header_name() -> &'static str { | ||||||
|                 $n |                 static NAME: &'static str = $n; | ||||||
|  |                 NAME | ||||||
|             } |             } | ||||||
|             fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> { |             fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> { | ||||||
|                 $crate::header::parsing::from_comma_delimited(raw).map($id) |                 $crate::header::parsing::from_comma_delimited(raw).map($id) | ||||||
| @@ -268,7 +270,8 @@ macro_rules! header { | |||||||
|         __hyper__deref!($id => $value); |         __hyper__deref!($id => $value); | ||||||
|         impl $crate::header::Header for $id { |         impl $crate::header::Header for $id { | ||||||
|             fn header_name() -> &'static str { |             fn header_name() -> &'static str { | ||||||
|                 $n |                 static NAME: &'static str = $n; | ||||||
|  |                 NAME | ||||||
|             } |             } | ||||||
|             fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> { |             fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> { | ||||||
|                 $crate::header::parsing::from_one_raw_str(raw).map($id) |                 $crate::header::parsing::from_one_raw_str(raw).map($id) | ||||||
| @@ -296,7 +299,8 @@ macro_rules! header { | |||||||
|         } |         } | ||||||
|         impl $crate::header::Header for $id { |         impl $crate::header::Header for $id { | ||||||
|             fn header_name() -> &'static str { |             fn header_name() -> &'static str { | ||||||
|                 $n |                 static NAME: &'static str = $n; | ||||||
|  |                 NAME | ||||||
|             } |             } | ||||||
|             fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> { |             fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> { | ||||||
|                 // FIXME: Return None if no item is in $id::Only |                 // FIXME: Return None if no item is in $id::Only | ||||||
|   | |||||||
| @@ -40,7 +40,8 @@ pub enum Pragma { | |||||||
|  |  | ||||||
| impl Header for Pragma { | impl Header for Pragma { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Pragma" |         static NAME: &'static str = "Pragma"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Pragma> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Pragma> { | ||||||
|   | |||||||
| @@ -52,7 +52,8 @@ __hyper__deref!(Prefer => Vec<Preference>); | |||||||
|  |  | ||||||
| impl Header for Prefer { | impl Header for Prefer { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Prefer" |         static NAME: &'static str = "Prefer"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Prefer> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Prefer> { | ||||||
|   | |||||||
| @@ -50,7 +50,8 @@ __hyper__deref!(PreferenceApplied => Vec<Preference>); | |||||||
|  |  | ||||||
| impl Header for PreferenceApplied { | impl Header for PreferenceApplied { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Preference-Applied" |         static NAME: &'static str = "Preference-Applied"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<PreferenceApplied> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<PreferenceApplied> { | ||||||
|   | |||||||
| @@ -176,7 +176,8 @@ impl FromStr for ByteRangeSpec { | |||||||
| impl Header for Range { | impl Header for Range { | ||||||
|  |  | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Range" |         static NAME: &'static str = "Range"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Range> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Range> { | ||||||
|   | |||||||
| @@ -84,7 +84,8 @@ __hyper__deref!(SetCookie => Vec<CookiePair>); | |||||||
|  |  | ||||||
| impl Header for SetCookie { | impl Header for SetCookie { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Set-Cookie" |         static NAME: &'static str = "Set-Cookie"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<SetCookie> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<SetCookie> { | ||||||
|   | |||||||
| @@ -121,7 +121,8 @@ impl FromStr for StrictTransportSecurity { | |||||||
|  |  | ||||||
| impl Header for StrictTransportSecurity { | impl Header for StrictTransportSecurity { | ||||||
|     fn header_name() -> &'static str { |     fn header_name() -> &'static str { | ||||||
|         "Strict-Transport-Security" |         static NAME: &'static str = "Strict-Transport-Security"; | ||||||
|  |         NAME | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<StrictTransportSecurity> { |     fn parse_header(raw: &[Vec<u8>]) -> ::Result<StrictTransportSecurity> { | ||||||
|   | |||||||
| @@ -1,4 +1,6 @@ | |||||||
| pub use self::item::Item; | pub use self::item::Item; | ||||||
|  | pub use self::vec_map::{VecMap, Entry}; | ||||||
|  |  | ||||||
| mod cell; | mod cell; | ||||||
| mod item; | mod item; | ||||||
|  | mod vec_map; | ||||||
|   | |||||||
							
								
								
									
										89
									
								
								src/header/internals/vec_map.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/header/internals/vec_map.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | |||||||
|  | #[derive(Clone)] | ||||||
|  | pub struct VecMap<K, V> { | ||||||
|  |     vec: Vec<(K, V)>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<K: PartialEq, V> VecMap<K, V> { | ||||||
|  |     pub fn new() -> VecMap<K, V> { | ||||||
|  |         VecMap { | ||||||
|  |             vec: Vec::new() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn insert(&mut self, key: K, value: V) { | ||||||
|  |         match self.find(&key) { | ||||||
|  |             Some(pos) => self.vec[pos] = (key, value), | ||||||
|  |             None => self.vec.push((key, value)) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn entry(&mut self, key: K) -> Entry<K, V> { | ||||||
|  |         match self.find(&key) { | ||||||
|  |             Some(pos) => Entry::Occupied(OccupiedEntry { | ||||||
|  |                 vec: self, | ||||||
|  |                 pos: pos, | ||||||
|  |             }), | ||||||
|  |             None => Entry::Vacant(VacantEntry { | ||||||
|  |                 vec: self, | ||||||
|  |                 key: key, | ||||||
|  |             }) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn get(&self, key: &K) -> Option<&V> { | ||||||
|  |         self.find(key).map(move |pos| &self.vec[pos].1) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { | ||||||
|  |         self.find(key).map(move |pos| &mut self.vec[pos].1) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn contains_key(&self, key: &K) -> bool { | ||||||
|  |         self.find(key).is_some() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn len(&self) -> usize { self.vec.len() } | ||||||
|  |     pub fn iter(&self) -> ::std::slice::Iter<(K, V)> { | ||||||
|  |         self.vec.iter() | ||||||
|  |     } | ||||||
|  |     pub fn remove(&mut self, key: &K) -> Option<V> { | ||||||
|  |         self.find(key).map(|pos| self.vec.remove(pos)).map(|(_, v)| v) | ||||||
|  |     } | ||||||
|  |     pub fn clear(&mut self) { | ||||||
|  |         self.vec.clear(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn find(&self, key: &K) -> Option<usize> { | ||||||
|  |         self.vec.iter().position(|entry| key == &entry.0) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub enum Entry<'a, K: 'a, V: 'a> { | ||||||
|  |     Vacant(VacantEntry<'a, K, V>), | ||||||
|  |     Occupied(OccupiedEntry<'a, K, V>) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub struct VacantEntry<'a, K: 'a, V: 'a> { | ||||||
|  |     vec: &'a mut VecMap<K, V>, | ||||||
|  |     key: K, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<'a, K, V> VacantEntry<'a, K, V> { | ||||||
|  |     pub fn insert(self, val: V) -> &'a mut V { | ||||||
|  |         let mut vec = self.vec; | ||||||
|  |         vec.vec.push((self.key, val)); | ||||||
|  |         let pos = vec.vec.len() - 1; | ||||||
|  |         &mut vec.vec[pos].1 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub struct OccupiedEntry<'a, K: 'a, V: 'a> { | ||||||
|  |     vec: &'a mut VecMap<K, V>, | ||||||
|  |     pos: usize, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<'a, K, V> OccupiedEntry<'a, K, V> { | ||||||
|  |     pub fn into_mut(self) -> &'a mut V { | ||||||
|  |         &mut self.vec.vec[self.pos].1 | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -77,17 +77,16 @@ | |||||||
| //! ``` | //! ``` | ||||||
| use std::any::Any; | use std::any::Any; | ||||||
| use std::borrow::{Cow, ToOwned}; | use std::borrow::{Cow, ToOwned}; | ||||||
| use std::collections::HashMap; | //use std::collections::HashMap; | ||||||
| use std::collections::hash_map::{Iter, Entry}; | //use std::collections::hash_map::{Iter, Entry}; | ||||||
| use std::iter::{FromIterator, IntoIterator}; | use std::iter::{FromIterator, IntoIterator}; | ||||||
| use std::ops::{Deref, DerefMut}; |  | ||||||
| use std::{mem, fmt}; | use std::{mem, fmt}; | ||||||
|  |  | ||||||
| use {httparse, traitobject}; | use {httparse, traitobject}; | ||||||
| use typeable::Typeable; | use typeable::Typeable; | ||||||
| use unicase::UniCase; | use unicase::UniCase; | ||||||
|  |  | ||||||
| use self::internals::Item; | use self::internals::{Item, VecMap, Entry}; | ||||||
|  |  | ||||||
| #[cfg(feature = "serde-serialization")] | #[cfg(feature = "serde-serialization")] | ||||||
| use serde::{Deserialize, Deserializer, Serialize, Serializer}; | use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||||||
| @@ -104,7 +103,6 @@ mod internals; | |||||||
| mod shared; | mod shared; | ||||||
| pub mod parsing; | pub mod parsing; | ||||||
|  |  | ||||||
| type HeaderName = UniCase<CowStr>; |  | ||||||
|  |  | ||||||
| /// A trait for any object that will represent a header field and value. | /// A trait for any object that will represent a header field and value. | ||||||
| /// | /// | ||||||
| @@ -169,7 +167,8 @@ fn header_name<T: Header>() -> &'static str { | |||||||
| /// A map of header fields on requests and responses. | /// A map of header fields on requests and responses. | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| pub struct Headers { | pub struct Headers { | ||||||
|     data: HashMap<HeaderName, Item> |     //data: HashMap<HeaderName, Item> | ||||||
|  |     data: VecMap<HeaderName, Item>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Default for Headers { | impl Default for Headers { | ||||||
| @@ -178,12 +177,58 @@ impl Default for Headers { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | macro_rules! literals { | ||||||
|  |     ($($len:expr => $($header:path),+;)+) => ( | ||||||
|  |         fn maybe_literal(s: &str) -> Cow<'static, str> { | ||||||
|  |             match s.len() { | ||||||
|  |                 $($len => { | ||||||
|  |                     $( | ||||||
|  |                     if UniCase(<$header>::header_name()) == s { | ||||||
|  |                         return Cow::Borrowed(<$header>::header_name()); | ||||||
|  |                     } | ||||||
|  |                     )+ | ||||||
|  |                 })+ | ||||||
|  |  | ||||||
|  |                 _ => () | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             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 { | impl Headers { | ||||||
|  |  | ||||||
|     /// Creates a new, empty headers map. |     /// Creates a new, empty headers map. | ||||||
|     pub fn new() -> Headers { |     pub fn new() -> Headers { | ||||||
|         Headers { |         Headers { | ||||||
|             data: HashMap::new() |             data: VecMap::new() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -192,7 +237,7 @@ impl Headers { | |||||||
|         let mut headers = Headers::new(); |         let mut headers = Headers::new(); | ||||||
|         for header in raw { |         for header in raw { | ||||||
|             trace!("raw header: {:?}={:?}", header.name, &header.value[..]); |             trace!("raw header: {:?}={:?}", header.name, &header.value[..]); | ||||||
|             let name = UniCase(CowStr(Cow::Owned(header.name.to_owned()))); |             let name = HeaderName(UniCase(maybe_literal(header.name))); | ||||||
|             let mut item = match headers.data.entry(name) { |             let mut item = match headers.data.entry(name) { | ||||||
|                 Entry::Vacant(entry) => entry.insert(Item::new_raw(vec![])), |                 Entry::Vacant(entry) => entry.insert(Item::new_raw(vec![])), | ||||||
|                 Entry::Occupied(entry) => entry.into_mut() |                 Entry::Occupied(entry) => entry.into_mut() | ||||||
| @@ -209,7 +254,7 @@ impl Headers { | |||||||
|     /// The field is determined by the type of the value being set. |     /// The field is determined by the type of the value being set. | ||||||
|     pub fn set<H: Header>(&mut self, value: H) { |     pub fn set<H: Header>(&mut self, value: H) { | ||||||
|         trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), HeaderFormatter(&value)); |         trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), HeaderFormatter(&value)); | ||||||
|         self.data.insert(UniCase(CowStr(Cow::Borrowed(header_name::<H>()))), |         self.data.insert(HeaderName(UniCase(Cow::Borrowed(header_name::<H>()))), | ||||||
|                          Item::new_typed(Box::new(value))); |                          Item::new_typed(Box::new(value))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -226,7 +271,7 @@ impl Headers { | |||||||
|     /// ``` |     /// ``` | ||||||
|     pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> { |     pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> { | ||||||
|         self.data |         self.data | ||||||
|             .get(&UniCase(CowStr(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) })))) |             .get(&HeaderName(UniCase(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) })))) | ||||||
|             .map(Item::raw) |             .map(Item::raw) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -242,26 +287,26 @@ impl Headers { | |||||||
|     pub fn set_raw<K: Into<Cow<'static, str>> + fmt::Debug>(&mut self, name: K, |     pub fn set_raw<K: Into<Cow<'static, str>> + fmt::Debug>(&mut self, name: K, | ||||||
|             value: Vec<Vec<u8>>) { |             value: Vec<Vec<u8>>) { | ||||||
|         trace!("Headers.set_raw( {:?}, {:?} )", name, value); |         trace!("Headers.set_raw( {:?}, {:?} )", name, value); | ||||||
|         self.data.insert(UniCase(CowStr(name.into())), Item::new_raw(value)); |         self.data.insert(HeaderName(UniCase(name.into())), Item::new_raw(value)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Remove a header set by set_raw |     /// Remove a header set by set_raw | ||||||
|     pub fn remove_raw(&mut self, name: &str) { |     pub fn remove_raw(&mut self, name: &str) { | ||||||
|         trace!("Headers.remove_raw( {:?} )", name); |         trace!("Headers.remove_raw( {:?} )", name); | ||||||
|         self.data.remove( |         self.data.remove( | ||||||
|             &UniCase(CowStr(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))) |             &HeaderName(UniCase(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))) | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get a reference to the header field's value, if it exists. |     /// Get a reference to the header field's value, if it exists. | ||||||
|     pub fn get<H: Header>(&self) -> Option<&H> { |     pub fn get<H: Header>(&self) -> Option<&H> { | ||||||
|         self.data.get(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))) |         self.data.get(&HeaderName(UniCase(Cow::Borrowed(header_name::<H>())))) | ||||||
|         .and_then(Item::typed::<H>) |         .and_then(Item::typed::<H>) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get a mutable reference to the header field's value, if it exists. |     /// Get a mutable reference to the header field's value, if it exists. | ||||||
|     pub fn get_mut<H: Header>(&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>())))) |         self.data.get_mut(&HeaderName(UniCase(Cow::Borrowed(header_name::<H>())))) | ||||||
|         .and_then(Item::typed_mut::<H>) |         .and_then(Item::typed_mut::<H>) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -276,14 +321,14 @@ impl Headers { | |||||||
|     /// let has_type = headers.has::<ContentType>(); |     /// let has_type = headers.has::<ContentType>(); | ||||||
|     /// ``` |     /// ``` | ||||||
|     pub fn has<H: Header>(&self) -> bool { |     pub fn has<H: Header>(&self) -> bool { | ||||||
|         self.data.contains_key(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))) |         self.data.contains_key(&HeaderName(UniCase(Cow::Borrowed(header_name::<H>())))) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Removes a header from the map, if one existed. |     /// Removes a header from the map, if one existed. | ||||||
|     /// Returns true if a header has been removed. |     /// Returns true if a header has been removed. | ||||||
|     pub fn remove<H: Header>(&mut self) -> bool { |     pub fn remove<H: Header>(&mut self) -> bool { | ||||||
|         trace!("Headers.remove( {:?} )", header_name::<H>()); |         trace!("Headers.remove( {:?} )", header_name::<H>()); | ||||||
|         self.data.remove(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))).is_some() |         self.data.remove(&HeaderName(UniCase(Cow::Borrowed(header_name::<H>())))).is_some() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Returns an iterator over the header fields. |     /// Returns an iterator over the header fields. | ||||||
| @@ -377,14 +422,14 @@ impl Deserialize for Headers { | |||||||
| /// An `Iterator` over the fields in a `Headers` map. | /// An `Iterator` over the fields in a `Headers` map. | ||||||
| #[allow(missing_debug_implementations)] | #[allow(missing_debug_implementations)] | ||||||
| pub struct HeadersItems<'a> { | pub struct HeadersItems<'a> { | ||||||
|     inner: Iter<'a, HeaderName, Item> |     inner: ::std::slice::Iter<'a, (HeaderName, Item)> | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a> Iterator for HeadersItems<'a> { | impl<'a> Iterator for HeadersItems<'a> { | ||||||
|     type Item = HeaderView<'a>; |     type Item = HeaderView<'a>; | ||||||
|  |  | ||||||
|     fn next(&mut self) -> Option<HeaderView<'a>> { |     fn next(&mut self) -> Option<HeaderView<'a>> { | ||||||
|         self.inner.next().map(|(k, v)| HeaderView(k, v)) |         self.inner.next().map(|&(ref k, ref v)| HeaderView(k, v)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -395,7 +440,7 @@ impl<'a> HeaderView<'a> { | |||||||
|     /// Check if a HeaderView is a certain Header. |     /// Check if a HeaderView is a certain Header. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn is<H: Header>(&self) -> bool { |     pub fn is<H: Header>(&self) -> bool { | ||||||
|         UniCase(CowStr(Cow::Borrowed(header_name::<H>()))) == *self.0 |         HeaderName(UniCase(Cow::Borrowed(header_name::<H>()))) == *self.0 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get the Header name as a slice. |     /// Get the Header name as a slice. | ||||||
| @@ -473,38 +518,30 @@ impl<'a, H: Header> fmt::Debug for HeaderFormatter<'a, H> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone, Hash, Eq, PartialEq, PartialOrd, Ord)] | #[derive(Clone, Debug)] | ||||||
| struct CowStr(Cow<'static, str>); | struct HeaderName(UniCase<Cow<'static, str>>); | ||||||
|  |  | ||||||
| impl Deref for CowStr { | impl fmt::Display for HeaderName { | ||||||
|     type Target = Cow<'static, str>; |  | ||||||
|  |  | ||||||
|     fn deref(&self) -> &Cow<'static, str> { |  | ||||||
|         &self.0 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl fmt::Debug for CowStr { |  | ||||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |  | ||||||
|         fmt::Debug::fmt(&self.0, f) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl fmt::Display for CowStr { |  | ||||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||||
|         fmt::Display::fmt(&self.0, f) |         fmt::Display::fmt(&self.0, f) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl DerefMut for CowStr { | impl AsRef<str> for HeaderName { | ||||||
|     fn deref_mut(&mut self) -> &mut Cow<'static, str> { |     fn as_ref(&self) -> &str { | ||||||
|         &mut self.0 |         ((self.0).0).as_ref() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl AsRef<str> for CowStr { | impl PartialEq for HeaderName { | ||||||
|     fn as_ref(&self) -> &str { |     fn eq(&self, other: &HeaderName) -> bool { | ||||||
|         self |         let s = self.as_ref(); | ||||||
|  |         let k = other.as_ref(); | ||||||
|  |         if s.len() == k.len() && s.as_ptr() == k.as_ptr() { | ||||||
|  |             true | ||||||
|  |         } else { | ||||||
|  |             self.0 == other.0 | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user