From a0c4edb6e52715df86ec857c45f5a7baa5ff243b Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Sun, 14 Sep 2014 10:26:47 -0700 Subject: [PATCH] adjust representation of internal Items --- src/header/mod.rs | 97 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 26 deletions(-) diff --git a/src/header/mod.rs b/src/header/mod.rs index 5ab93779..587c6ec1 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -7,6 +7,7 @@ use std::ascii::OwnedAsciiExt; use std::char::is_lowercase; use std::fmt::{mod, Show}; +use std::intrinsics::TypeId; use std::mem::{transmute, transmute_copy}; use std::raw::TraitObject; use std::str::{from_utf8, SendStr, Slice, Owned}; @@ -80,11 +81,8 @@ impl Headers { let name = unsafe { raw::from_utf8(name) }.into_ascii_lower(); - match headers.data.find_or_insert(Owned(name), Raw(vec![])) { - &Raw(ref mut pieces) => pieces.push(value), - // at this point, Raw is the only thing that has been inserted - _ => unreachable!() - } + let item = headers.data.find_or_insert(Owned(name), raw(vec![])); + item.raw.push(value); }, None => break, } @@ -96,7 +94,11 @@ impl Headers { /// /// The field is determined by the type of the value being set. pub fn set(&mut self, value: H) { - self.data.insert(Slice(header_name::()), Typed(box value)); + self.data.insert(Slice(header_name::()), Item { + raw: vec![], + tid: Some(TypeId::of::()), + typed: Some(box value as Box
) + }); } /// 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") }; /// ``` pub unsafe fn get_raw(&self, name: &'static str) -> Option<&[Vec]> { - self.data.find(&Slice(name)).and_then(|item| { - match *item { - Raw(ref raw) => Some(raw.as_slice()), - _ => None - } + self.data.find(&Slice(name)).map(|item| { + item.raw.as_slice() }) } @@ -138,28 +137,29 @@ impl Headers { pub fn get_ref(&mut self) -> Option<&H> { self.data.find_mut(&Slice(header_name::())).and_then(|item| { debug!("get_ref, name={}, val={}", header_name::(), item); - let header = match *item { - Raw(ref raw) => match Header::parse_header(raw.as_slice()) { + let expected_tid = TypeId::of::(); + 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 }, None => return None }, - Typed(..) => return Some(item) }; - *item = Typed(box header as Box
); + item.typed = Some(box header as Box
); + item.tid = Some(expected_tid); Some(item) }).and_then(|item| { debug!("downcasting {}", item); - let ret = match *item { - Typed(ref val) => { + let ret = match item.typed { + Some(ref val) => { unsafe { Some(val.downcast_ref_unchecked()) } }, - Raw(..) => unreachable!() + None => unreachable!() }; - debug!("returning {}", ret.is_some()); ret }) } @@ -238,21 +238,30 @@ impl Mutable for Headers { } } -enum Item { - Raw(Vec>), - Typed(Box
) +struct Item { + raw: Vec>, + tid: Option, + typed: Option>, +} + +fn raw(parts: Vec>) -> Item { + Item { + raw: parts, + tid: None, + typed: None, + } } impl fmt::Show for Item { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - Raw(ref v) => { - for part in v.iter() { + match self.typed { + Some(ref h) => h.fmt_header(fmt), + None => { + for part in self.raw.iter() { try!(fmt.write(part.as_slice())); } Ok(()) }, - Typed(ref h) => h.fmt_header(fmt) } } } @@ -260,6 +269,7 @@ impl fmt::Show for Item { #[cfg(test)] mod tests { use std::io::MemReader; + use std::fmt; use mime::{Mime, Text, Plain}; use super::{Headers, Header}; 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()); assert_eq!(content_type, Some(ContentType(Mime(Text, Plain, vec![])))); } + + #[deriving(Clone)] + struct CrazyLength(Option, uint); + + impl Header for CrazyLength { + fn header_name(_: Option) -> &'static str { + "content-length" + } + fn parse_header(raw: &[Vec]) -> Option { + 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::().unwrap(); + let CrazyLength(_, crazy_num) = headers.get::().unwrap(); + assert_eq!(num, crazy_num); + } }