adjust representation of internal Items
This commit is contained in:
		| @@ -7,6 +7,7 @@ | |||||||
| use std::ascii::OwnedAsciiExt; | use std::ascii::OwnedAsciiExt; | ||||||
| use std::char::is_lowercase; | use std::char::is_lowercase; | ||||||
| use std::fmt::{mod, Show}; | use std::fmt::{mod, Show}; | ||||||
|  | use std::intrinsics::TypeId; | ||||||
| use std::mem::{transmute, transmute_copy}; | use std::mem::{transmute, transmute_copy}; | ||||||
| use std::raw::TraitObject; | use std::raw::TraitObject; | ||||||
| use std::str::{from_utf8, SendStr, Slice, Owned}; | use std::str::{from_utf8, SendStr, Slice, Owned}; | ||||||
| @@ -80,11 +81,8 @@ impl Headers { | |||||||
|                     let name = unsafe { |                     let name = unsafe { | ||||||
|                         raw::from_utf8(name) |                         raw::from_utf8(name) | ||||||
|                     }.into_ascii_lower(); |                     }.into_ascii_lower(); | ||||||
|                     match headers.data.find_or_insert(Owned(name), Raw(vec![])) { |                     let item = headers.data.find_or_insert(Owned(name), raw(vec![])); | ||||||
|                         &Raw(ref mut pieces) => pieces.push(value), |                     item.raw.push(value); | ||||||
|                         // at this point, Raw is the only thing that has been inserted |  | ||||||
|                         _ => unreachable!() |  | ||||||
|                     } |  | ||||||
|                 }, |                 }, | ||||||
|                 None => break, |                 None => break, | ||||||
|             } |             } | ||||||
| @@ -96,7 +94,11 @@ 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>()), Typed(box value)); |         self.data.insert(Slice(header_name::<H>()), Item { | ||||||
|  |             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. | ||||||
| @@ -126,11 +128,8 @@ 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)).and_then(|item| { |         self.data.find(&Slice(name)).map(|item| { | ||||||
|             match *item { |             item.raw.as_slice() | ||||||
|                 Raw(ref raw) => Some(raw.as_slice()), |  | ||||||
|                 _ => None |  | ||||||
|             } |  | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -138,28 +137,29 @@ 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 header = match *item { |             let expected_tid = TypeId::of::<H>(); | ||||||
|                 Raw(ref raw) => match Header::parse_header(raw.as_slice()) { |             let header = match item.tid { | ||||||
|  |                 Some(tid) if tid == expected_tid => return Some(item), | ||||||
|  |                 _ => match Header::parse_header(item.raw.as_slice()) { | ||||||
|                     Some::<H>(h) => { |                     Some::<H>(h) => { | ||||||
|                         h |                         h | ||||||
|                     }, |                     }, | ||||||
|                     None => return None |                     None => return None | ||||||
|                 }, |                 }, | ||||||
|                 Typed(..) => return Some(item) |  | ||||||
|             }; |             }; | ||||||
|             *item = Typed(box header as Box<Header>); |             item.typed = Some(box header as Box<Header>); | ||||||
|  |             item.tid = Some(expected_tid); | ||||||
|             Some(item) |             Some(item) | ||||||
|         }).and_then(|item| { |         }).and_then(|item| { | ||||||
|             debug!("downcasting {}", item); |             debug!("downcasting {}", item); | ||||||
|             let ret = match *item { |             let ret = match item.typed { | ||||||
|                 Typed(ref val) => { |                 Some(ref val) => { | ||||||
|                     unsafe { |                     unsafe { | ||||||
|                         Some(val.downcast_ref_unchecked()) |                         Some(val.downcast_ref_unchecked()) | ||||||
|                     } |                     } | ||||||
|                 }, |                 }, | ||||||
|                 Raw(..) => unreachable!() |                 None => unreachable!() | ||||||
|             }; |             }; | ||||||
|             debug!("returning {}", ret.is_some()); |  | ||||||
|             ret |             ret | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| @@ -238,21 +238,30 @@ impl Mutable for Headers { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| enum Item { | struct Item { | ||||||
|     Raw(Vec<Vec<u8>>), |     raw: Vec<Vec<u8>>, | ||||||
|     Typed(Box<Header>) |     tid: Option<TypeId>, | ||||||
|  |     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 { |         match self.typed { | ||||||
|             Raw(ref v) => { |             Some(ref h) => h.fmt_header(fmt), | ||||||
|                 for part in v.iter() { |             None => { | ||||||
|  |                 for part in self.raw.iter() { | ||||||
|                     try!(fmt.write(part.as_slice())); |                     try!(fmt.write(part.as_slice())); | ||||||
|                 } |                 } | ||||||
|                 Ok(()) |                 Ok(()) | ||||||
|             }, |             }, | ||||||
|             Typed(ref h) => h.fmt_header(fmt) |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -260,6 +269,7 @@ impl fmt::Show for Item { | |||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     use std::io::MemReader; |     use std::io::MemReader; | ||||||
|  |     use std::fmt; | ||||||
|     use mime::{Mime, Text, Plain}; |     use mime::{Mime, Text, Plain}; | ||||||
|     use super::{Headers, Header}; |     use super::{Headers, Header}; | ||||||
|     use super::common::{ContentLength, ContentType}; |     use super::common::{ContentLength, ContentType}; | ||||||
| @@ -279,4 +289,39 @@ mod tests { | |||||||
|         let content_type = Header::parse_header(["text/plain".as_bytes().to_vec()].as_slice()); |         let content_type = Header::parse_header(["text/plain".as_bytes().to_vec()].as_slice()); | ||||||
|         assert_eq!(content_type, Some(ContentType(Mime(Text, Plain, vec![])))); |         assert_eq!(content_type, Some(ContentType(Mime(Text, Plain, vec![])))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     #[deriving(Clone)] | ||||||
|  |     struct CrazyLength(Option<bool>, uint); | ||||||
|  |  | ||||||
|  |     impl Header for CrazyLength { | ||||||
|  |         fn header_name(_: Option<CrazyLength>) -> &'static str { | ||||||
|  |             "content-length" | ||||||
|  |         } | ||||||
|  |         fn parse_header(raw: &[Vec<u8>]) -> Option<CrazyLength> { | ||||||
|  |             use std::str::from_utf8; | ||||||
|  |             use std::from_str::FromStr; | ||||||
|  |  | ||||||
|  |             if raw.len() != 1 { | ||||||
|  |                 return None; | ||||||
|  |             } | ||||||
|  |             // we JUST checked that raw.len() == 1, so raw[0] WILL exist. | ||||||
|  |             match from_utf8(unsafe { raw.as_slice().unsafe_get(0).as_slice() }) { | ||||||
|  |                 Some(s) => FromStr::from_str(s), | ||||||
|  |                 None => None | ||||||
|  |             }.map(|u| CrazyLength(Some(false), u)) | ||||||
|  |         } | ||||||
|  |         fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||||
|  |             use std::fmt::Show; | ||||||
|  |             let CrazyLength(_, ref value) = *self; | ||||||
|  |             value.fmt(fmt) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[test] | ||||||
|  |     fn test_different_structs_for_same_header() { | ||||||
|  |         let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap(); | ||||||
|  |         let ContentLength(num) = headers.get::<ContentLength>().unwrap(); | ||||||
|  |         let CrazyLength(_, crazy_num) = headers.get::<CrazyLength>().unwrap(); | ||||||
|  |         assert_eq!(num, crazy_num); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user