Refactor Header representation to not store the raw representation
This disallows reparsing, but since that can be a significant source of errors I think this is actually beneficial. This also refactors to avoid storing the TypeId, though that is less of a gain.
This commit is contained in:
		| @@ -15,6 +15,7 @@ use std::string::raw; | |||||||
| use std::collections::hashmap::{HashMap, Entries}; | use std::collections::hashmap::{HashMap, Entries}; | ||||||
|  |  | ||||||
| use uany::UncheckedAnyDowncast; | use uany::UncheckedAnyDowncast; | ||||||
|  | use typeable::Typeable; | ||||||
|  |  | ||||||
| use http::read_header; | use http::read_header; | ||||||
| use {HttpResult}; | use {HttpResult}; | ||||||
| @@ -23,7 +24,7 @@ use {HttpResult}; | |||||||
| pub mod common; | pub mod common; | ||||||
|  |  | ||||||
| /// 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. | ||||||
| pub trait Header: 'static { | pub trait Header: Typeable { | ||||||
|     /// Returns the name of the header field this belongs to. |     /// Returns the name of the header field this belongs to. | ||||||
|     /// |     /// | ||||||
|     /// The market `Option` is to hint to the type system which implementation |     /// The market `Option` is to hint to the type system which implementation | ||||||
| @@ -41,7 +42,18 @@ pub trait Header: 'static { | |||||||
|     fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result; |     fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result; | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a> UncheckedAnyDowncast<'a> for &'a Header + 'a { | #[doc(hidden)] | ||||||
|  | trait Is { | ||||||
|  |     fn is<T: 'static>(self) -> bool; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<'a> Is for &'a Header { | ||||||
|  |     fn is<T: 'static>(self) -> bool { | ||||||
|  |         self.get_type() == TypeId::of::<T>() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<'a> UncheckedAnyDowncast<'a> for &'a Header { | ||||||
|     #[inline] |     #[inline] | ||||||
|     unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T { |     unsafe fn downcast_ref_unchecked<T: 'static>(self) -> &'a T { | ||||||
|         let to: TraitObject = transmute_copy(&self); |         let to: TraitObject = transmute_copy(&self); | ||||||
| @@ -81,8 +93,12 @@ impl Headers { | |||||||
|                     let name = unsafe { |                     let name = unsafe { | ||||||
|                         raw::from_utf8(name) |                         raw::from_utf8(name) | ||||||
|                     }.into_ascii_lower(); |                     }.into_ascii_lower(); | ||||||
|                     let item = headers.data.find_or_insert(Owned(name), raw(vec![])); |                     let item = headers.data.find_or_insert(Owned(name), Raw(vec![])); | ||||||
|                     item.raw.push(value); |                     match *item { | ||||||
|  |                         Raw(ref mut raw) => raw.push(value), | ||||||
|  |                         // Unreachable | ||||||
|  |                         _ => {} | ||||||
|  |                     }; | ||||||
|                 }, |                 }, | ||||||
|                 None => break, |                 None => break, | ||||||
|             } |             } | ||||||
| @@ -94,11 +110,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) { | ||||||
|         self.data.insert(Slice(header_name::<H>()), Item { |         self.data.insert(Slice(header_name::<H>()), Typed(box value as Box<Header>)); | ||||||
|             raw: vec![], |  | ||||||
|             tid: Some(TypeId::of::<H>()), |  | ||||||
|             typed: Some(box value as Box<Header>) |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get a clone of the header field's value, if it exists. |     /// Get a clone of the header field's value, if it exists. | ||||||
| @@ -128,8 +140,11 @@ impl Headers { | |||||||
|     /// let raw_content_type = unsafe { headers.get_raw("content-type") }; |     /// let raw_content_type = unsafe { headers.get_raw("content-type") }; | ||||||
|     /// ``` |     /// ``` | ||||||
|     pub unsafe fn get_raw(&self, name: &'static str) -> Option<&[Vec<u8>]> { |     pub unsafe fn get_raw(&self, name: &'static str) -> Option<&[Vec<u8>]> { | ||||||
|         self.data.find(&Slice(name)).map(|item| { |         self.data.find(&Slice(name)).and_then(|item| { | ||||||
|             item.raw.as_slice() |             match *item { | ||||||
|  |                 Raw(ref raw) => Some(raw.as_slice()), | ||||||
|  |                 _ => None | ||||||
|  |             } | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -137,28 +152,35 @@ impl Headers { | |||||||
|     pub fn get_ref<H: Header>(&mut self) -> Option<&H> { |     pub fn get_ref<H: Header>(&mut self) -> Option<&H> { | ||||||
|         self.data.find_mut(&Slice(header_name::<H>())).and_then(|item| { |         self.data.find_mut(&Slice(header_name::<H>())).and_then(|item| { | ||||||
|             debug!("get_ref, name={}, val={}", header_name::<H>(), item); |             debug!("get_ref, name={}, val={}", header_name::<H>(), item); | ||||||
|             let expected_tid = TypeId::of::<H>(); |             let header = match *item { | ||||||
|             let header = match item.tid { |                 // Huge borrowck hack here, should be refactored to just return here. | ||||||
|                 Some(tid) if tid == expected_tid => return Some(item), |                 Typed(ref typed) if typed.is::<H>() => None, | ||||||
|                 _ => match Header::parse_header(item.raw.as_slice()) { |                 // Typed, wrong type | ||||||
|  |                 Typed(_) => return None, | ||||||
|  |                 Raw(ref raw) => match Header::parse_header(raw.as_slice()) { | ||||||
|                     Some::<H>(h) => { |                     Some::<H>(h) => { | ||||||
|                         h |                         Some(h) | ||||||
|                     }, |                     }, | ||||||
|                     None => return None |                     None => return None | ||||||
|                 }, |                 }, | ||||||
|             }; |             }; | ||||||
|             item.typed = Some(box header as Box<Header>); |  | ||||||
|             item.tid = Some(expected_tid); |             match header { | ||||||
|  |                 Some(header) => { | ||||||
|  |                     *item = Typed(box header as Box<Header>); | ||||||
|                     Some(item) |                     Some(item) | ||||||
|  |                 }, | ||||||
|  |                 None => { | ||||||
|  |                     Some(item) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         }).and_then(|item| { |         }).and_then(|item| { | ||||||
|             debug!("downcasting {}", item); |             debug!("downcasting {}", item); | ||||||
|             let ret = match item.typed { |             let ret = match *item { | ||||||
|                 Some(ref val) => { |                 Typed(ref val) => { | ||||||
|                     unsafe { |                     unsafe { Some(val.downcast_ref_unchecked()) } | ||||||
|                         Some(val.downcast_ref_unchecked()) |  | ||||||
|                     } |  | ||||||
|                 }, |                 }, | ||||||
|                 None => unreachable!() |                 _ => unreachable!() | ||||||
|             }; |             }; | ||||||
|             ret |             ret | ||||||
|         }) |         }) | ||||||
| @@ -181,7 +203,7 @@ impl Headers { | |||||||
|     /// 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 { | ||||||
|         self.data.pop_equiv(&Header::header_name(None::<H>)).is_some() |         self.data.remove(&Slice(Header::header_name(None::<H>))) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Returns an iterator over the header fields. |     /// Returns an iterator over the header fields. | ||||||
| @@ -238,26 +260,17 @@ impl Mutable for Headers { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| struct Item { | enum Item { | ||||||
|     raw: Vec<Vec<u8>>, |     Raw(Vec<Vec<u8>>), | ||||||
|     tid: Option<TypeId>, |     Typed(Box<Header>) | ||||||
|     typed: Option<Box<Header>>, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fn raw(parts: Vec<Vec<u8>>) -> Item { |  | ||||||
|     Item { |  | ||||||
|         raw: parts, |  | ||||||
|         tid: None, |  | ||||||
|         typed: None, |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| impl fmt::Show for Item { | impl fmt::Show for Item { | ||||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||||
|         match self.typed { |         match *self { | ||||||
|             Some(ref h) => h.fmt_header(fmt), |             Typed(ref h) => h.fmt_header(fmt), | ||||||
|             None => { |             Raw(ref raw) => { | ||||||
|                 for part in self.raw.iter() { |                 for part in raw.iter() { | ||||||
|                     try!(fmt.write(part.as_slice())); |                     try!(fmt.write(part.as_slice())); | ||||||
|                 } |                 } | ||||||
|                 Ok(()) |                 Ok(()) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user