Merge pull request #38 from reem/persistent-headers

Refactor Header representation to not store the raw representation
This commit is contained in:
Sean McArthur
2014-09-16 19:05:54 -07:00
3 changed files with 61 additions and 45 deletions

View File

@@ -22,6 +22,9 @@ git = "https://github.com/reem/rust-intertwine"
[dependencies.move-acceptor] [dependencies.move-acceptor]
git = "https://github.com/reem/rust-move-acceptor" git = "https://github.com/reem/rust-move-acceptor"
[dependencies.typeable]
git = "https://github.com/reem/rust-typeable"
[dev-dependencies.curl] [dev-dependencies.curl]
git = "https://github.com/carllerche/curl-rust" git = "https://github.com/carllerche/curl-rust"

View File

@@ -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(item) Some(header) => {
*item = Typed(box header as Box<Header>);
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(())
@@ -320,8 +333,7 @@ mod tests {
#[test] #[test]
fn test_different_structs_for_same_header() { fn test_different_structs_for_same_header() {
let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap(); let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap();
let ContentLength(num) = headers.get::<ContentLength>().unwrap(); let ContentLength(_) = headers.get::<ContentLength>().unwrap();
let CrazyLength(_, crazy_num) = headers.get::<CrazyLength>().unwrap(); assert!(headers.get::<CrazyLength>().is_none());
assert_eq!(num, crazy_num);
} }
} }

View File

@@ -12,6 +12,7 @@ extern crate openssl;
extern crate "unsafe-any" as uany; extern crate "unsafe-any" as uany;
extern crate "move-acceptor" as macceptor; extern crate "move-acceptor" as macceptor;
extern crate intertwine; extern crate intertwine;
extern crate typeable;
pub use std::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr, Port}; pub use std::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr, Port};
pub use mimewrapper::mime; pub use mimewrapper::mime;