Split Header into Header and HeaderFormat
Header contains all of the trait-object unsafe methods including the name of the header and parsing. HeaderFormat contains fmt_header, which is the only trait-object safe method.
This commit is contained in:
		| @@ -6,24 +6,26 @@ | |||||||
| //! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others. | //! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others. | ||||||
| use std::ascii::{AsciiExt, ASCII_LOWER_MAP}; | use std::ascii::{AsciiExt, ASCII_LOWER_MAP}; | ||||||
| use std::fmt::{mod, Show}; | use std::fmt::{mod, Show}; | ||||||
| use std::hash; |  | ||||||
| use std::intrinsics::TypeId; | use std::intrinsics::TypeId; | ||||||
| use std::mem::{transmute, transmute_copy}; |  | ||||||
| use std::raw::TraitObject; | use std::raw::TraitObject; | ||||||
| use std::str::{SendStr, Slice, Owned}; | use std::str::{SendStr, Slice, Owned}; | ||||||
| use std::collections::hashmap::{HashMap, Entries, Occupied, Vacant}; | use std::collections::hashmap::{HashMap, Entries, Occupied, Vacant}; | ||||||
| use std::sync::RWLock; | use std::sync::RWLock; | ||||||
|  | use std::{hash, mem}; | ||||||
|  |  | ||||||
| use uany::{UncheckedAnyDowncast, UncheckedAnyMutDowncast}; | use uany::{UncheckedAnyDowncast, UncheckedAnyMutDowncast}; | ||||||
| use typeable::Typeable; | use typeable::Typeable; | ||||||
|  |  | ||||||
| use http::{read_header, LineEnding}; | use http::{mod, LineEnding}; | ||||||
| use {HttpResult}; | use {HttpResult}; | ||||||
|  |  | ||||||
| /// Common Headers | /// Common Headers | ||||||
| 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. | ||||||
|  | /// | ||||||
|  | /// This trait represents the construction and identification of headers, | ||||||
|  | /// and contains trait-object unsafe methods. | ||||||
| pub trait Header: Typeable + Send + Sync { | pub trait Header: Typeable + Send + Sync { | ||||||
|     /// Returns the name of the header field this belongs to. |     /// Returns the name of the header field this belongs to. | ||||||
|     /// |     /// | ||||||
| @@ -38,7 +40,16 @@ pub trait Header: Typeable + Send + Sync { | |||||||
|     /// than one field value. If that's the case, you **should** return `None` |     /// than one field value. If that's the case, you **should** return `None` | ||||||
|     /// if `raw.len() > 1`. |     /// if `raw.len() > 1`. | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> Option<Self>; |     fn parse_header(raw: &[Vec<u8>]) -> Option<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: Typeable + Send + Sync { | ||||||
|     /// Format a header to be output into a TcpStream. |     /// 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, fmt: &mut fmt::Formatter) -> fmt::Result; |     fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -47,29 +58,29 @@ trait Is { | |||||||
|     fn is<T: 'static>(self) -> bool; |     fn is<T: 'static>(self) -> bool; | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a> Is for &'a Header { | impl<'a> Is for &'a HeaderFormat { | ||||||
|     fn is<T: 'static>(self) -> bool { |     fn is<T: 'static>(self) -> bool { | ||||||
|         self.get_type() == TypeId::of::<T>() |         self.get_type() == TypeId::of::<T>() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a> UncheckedAnyDowncast<'a> for &'a Header { | impl<'a> UncheckedAnyDowncast<'a> for &'a HeaderFormat { | ||||||
|     #[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 = mem::transmute_copy(&self); | ||||||
|         transmute(to.data) |         mem::transmute(to.data) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a> UncheckedAnyMutDowncast<'a> for &'a mut Header { | impl<'a> UncheckedAnyMutDowncast<'a> for &'a mut HeaderFormat { | ||||||
|     #[inline] |     #[inline] | ||||||
|     unsafe fn downcast_mut_unchecked<T: 'static>(self) -> &'a mut T { |     unsafe fn downcast_mut_unchecked<T: 'static>(self) -> &'a mut T { | ||||||
|         let to: TraitObject = transmute_copy(&self); |         let to: TraitObject = mem::transmute_copy(&self); | ||||||
|         transmute(to.data) |         mem::transmute(to.data) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fn header_name<T: Header>() -> &'static str { | fn header_name<T: Header + HeaderFormat>() -> &'static str { | ||||||
|     let name = Header::header_name(None::<T>); |     let name = Header::header_name(None::<T>); | ||||||
|     name |     name | ||||||
| } | } | ||||||
| @@ -92,7 +103,7 @@ impl Headers { | |||||||
|     pub fn from_raw<R: Reader>(rdr: &mut R) -> HttpResult<Headers> { |     pub fn from_raw<R: Reader>(rdr: &mut R) -> HttpResult<Headers> { | ||||||
|         let mut headers = Headers::new(); |         let mut headers = Headers::new(); | ||||||
|         loop { |         loop { | ||||||
|             match try!(read_header(rdr)) { |             match try!(http::read_header(rdr)) { | ||||||
|                 Some((name, value)) => { |                 Some((name, value)) => { | ||||||
|                     let name = CaseInsensitive(Owned(name)); |                     let name = CaseInsensitive(Owned(name)); | ||||||
|                     let item = match headers.data.entry(name) { |                     let item = match headers.data.entry(name) { | ||||||
| @@ -115,9 +126,9 @@ impl Headers { | |||||||
|     /// Set a header field to the corresponding value. |     /// Set a header field to the corresponding value. | ||||||
|     /// |     /// | ||||||
|     /// 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 + HeaderFormat>(&mut self, value: H) { | ||||||
|         self.data.insert(CaseInsensitive(Slice(header_name::<H>())), |         self.data.insert(CaseInsensitive(Slice(header_name::<H>())), | ||||||
|                          RWLock::new(Item::typed(box value as Box<Header + Send + Sync>))); |                          RWLock::new(Item::typed(box value as Box<HeaderFormat + Send + Sync>))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Access the raw value of a header. |     /// Access the raw value of a header. | ||||||
| @@ -135,13 +146,13 @@ impl Headers { | |||||||
|         self.data.find_equiv(&CaseInsensitive(name)).and_then(|item| { |         self.data.find_equiv(&CaseInsensitive(name)).and_then(|item| { | ||||||
|             let lock = item.read(); |             let lock = item.read(); | ||||||
|             if let Some(ref raw) = lock.raw { |             if let Some(ref raw) = lock.raw { | ||||||
|                 return unsafe { transmute(Some(raw[])) }; |                 return unsafe { mem::transmute(Some(raw[])) }; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             let mut lock = item.write(); |             let mut lock = item.write(); | ||||||
|             let raw = vec![lock.typed.as_ref().unwrap().to_string().into_bytes()]; |             let raw = vec![lock.typed.as_ref().unwrap().to_string().into_bytes()]; | ||||||
|             lock.raw = Some(raw); |             lock.raw = Some(raw); | ||||||
|             unsafe { transmute(Some(lock.raw.as_ref().unwrap()[])) } |             unsafe { mem::transmute(Some(lock.raw.as_ref().unwrap()[])) } | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -159,7 +170,7 @@ impl Headers { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// 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 + HeaderFormat>(&self) -> Option<&H> { | ||||||
|         self.get_or_parse::<H>().map(|item| { |         self.get_or_parse::<H>().map(|item| { | ||||||
|             let read = item.read(); |             let read = item.read(); | ||||||
|             debug!("downcasting {}", *read); |             debug!("downcasting {}", *read); | ||||||
| @@ -167,12 +178,12 @@ impl Headers { | |||||||
|                 Some(ref val) => unsafe { val.downcast_ref_unchecked() }, |                 Some(ref val) => unsafe { val.downcast_ref_unchecked() }, | ||||||
|                 _ => unreachable!() |                 _ => unreachable!() | ||||||
|             }; |             }; | ||||||
|             unsafe { transmute::<&H, &H>(ret) } |             unsafe { mem::transmute::<&H, &H>(ret) } | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// 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 + HeaderFormat>(&mut self) -> Option<&mut H> { | ||||||
|         self.get_or_parse::<H>().map(|item| { |         self.get_or_parse::<H>().map(|item| { | ||||||
|             let mut write = item.write(); |             let mut write = item.write(); | ||||||
|             debug!("downcasting {}", *write); |             debug!("downcasting {}", *write); | ||||||
| @@ -180,11 +191,11 @@ impl Headers { | |||||||
|                 Some(ref mut val) => unsafe { val.downcast_mut_unchecked() }, |                 Some(ref mut val) => unsafe { val.downcast_mut_unchecked() }, | ||||||
|                 _ => unreachable!() |                 _ => unreachable!() | ||||||
|             }; |             }; | ||||||
|             unsafe { transmute::<&mut H, &mut H>(ret) } |             unsafe { mem::transmute::<&mut H, &mut H>(ret) } | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_or_parse<H: Header>(&self) -> Option<&RWLock<Item>> { |     fn get_or_parse<H: Header + HeaderFormat>(&self) -> Option<&RWLock<Item>> { | ||||||
|         self.data.find(&CaseInsensitive(Slice(header_name::<H>()))).and_then(|item| { |         self.data.find(&CaseInsensitive(Slice(header_name::<H>()))).and_then(|item| { | ||||||
|             match item.read().typed { |             match item.read().typed { | ||||||
|                 Some(ref typed) if typed.is::<H>() => return Some(item), |                 Some(ref typed) if typed.is::<H>() => return Some(item), | ||||||
| @@ -226,7 +237,7 @@ impl Headers { | |||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             // Mutate! |             // Mutate! | ||||||
|             write.typed = Some(box header as Box<Header + Send + Sync>); |             write.typed = Some(box header as Box<HeaderFormat + Send + Sync>); | ||||||
|             Some(item) |             Some(item) | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| @@ -241,13 +252,13 @@ impl Headers { | |||||||
|     /// # let mut headers = Headers::new(); |     /// # let mut headers = Headers::new(); | ||||||
|     /// let has_type = headers.has::<ContentType>(); |     /// let has_type = headers.has::<ContentType>(); | ||||||
|     /// ``` |     /// ``` | ||||||
|     pub fn has<H: Header>(&self) -> bool { |     pub fn has<H: Header + HeaderFormat>(&self) -> bool { | ||||||
|         self.data.contains_key(&CaseInsensitive(Slice(header_name::<H>()))) |         self.data.contains_key(&CaseInsensitive(Slice(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 + HeaderFormat>(&mut self) -> bool { | ||||||
|         self.data.remove(&CaseInsensitive(Slice(Header::header_name(None::<H>)))) |         self.data.remove(&CaseInsensitive(Slice(Header::header_name(None::<H>)))) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -306,7 +317,7 @@ impl Mutable for Headers { | |||||||
|  |  | ||||||
| struct Item { | struct Item { | ||||||
|     raw: Option<Vec<Vec<u8>>>, |     raw: Option<Vec<Vec<u8>>>, | ||||||
|     typed: Option<Box<Header + Send + Sync>> |     typed: Option<Box<HeaderFormat + Send + Sync>> | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Item { | impl Item { | ||||||
| @@ -317,7 +328,7 @@ impl Item { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn typed(ty: Box<Header + Send + Sync>) -> Item { |     fn typed(ty: Box<HeaderFormat + Send + Sync>) -> Item { | ||||||
|         Item { |         Item { | ||||||
|             raw: None, |             raw: None, | ||||||
|             typed: Some(ty), |             typed: Some(ty), | ||||||
| @@ -342,7 +353,7 @@ impl fmt::Show for Item { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl fmt::Show for Box<Header + Send + Sync> { | impl fmt::Show for Box<HeaderFormat + Send + Sync> { | ||||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||||
|         (**self).fmt_header(fmt) |         (**self).fmt_header(fmt) | ||||||
|     } |     } | ||||||
| @@ -457,6 +468,9 @@ mod tests { | |||||||
|                 None => None |                 None => None | ||||||
|             }.map(|u| CrazyLength(Some(false), u)) |             }.map(|u| CrazyLength(Some(false), u)) | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     impl HeaderFormat for CrazyLength { | ||||||
|         fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |         fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||||
|             let CrazyLength(ref opt, ref value) = *self; |             let CrazyLength(ref opt, ref value) = *self; | ||||||
|             write!(fmt, "{}, {}", opt, value) |             write!(fmt, "{}, {}", opt, value) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user