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