Merge pull request #92 from reem/header-trait-split

Split Header into Header and HeaderFormat
This commit is contained in:
Sean McArthur
2014-10-31 15:20:55 -07:00
12 changed files with 80 additions and 44 deletions

View File

@@ -1,4 +1,4 @@
use header::Header; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{mod, Show};
use std::str::from_utf8; use std::str::from_utf8;
use mime::Mime; use mime::Mime;
@@ -49,7 +49,9 @@ impl Header for Accept {
None None
} }
} }
}
impl HeaderFormat for Accept {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let Accept(ref value) = *self; let Accept(ref value) = *self;
let last = value.len() - 1; let last = value.len() - 1;

View File

@@ -1,4 +1,4 @@
use header::Header; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{mod, Show};
use super::{from_comma_delimited, fmt_comma_delimited}; use super::{from_comma_delimited, fmt_comma_delimited};
use std::from_str::FromStr; use std::from_str::FromStr;
@@ -53,7 +53,9 @@ impl Header for Connection {
fn parse_header(raw: &[Vec<u8>]) -> Option<Connection> { fn parse_header(raw: &[Vec<u8>]) -> Option<Connection> {
from_comma_delimited(raw).map(|vec| Connection(vec)) from_comma_delimited(raw).map(|vec| Connection(vec))
} }
}
impl HeaderFormat for Connection {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let Connection(ref parts) = *self; let Connection(ref parts) = *self;
fmt_comma_delimited(fmt, parts[]) fmt_comma_delimited(fmt, parts[])

View File

@@ -1,6 +1,6 @@
use std::fmt::{mod, Show}; use std::fmt::{mod, Show};
use header::Header; use header::{Header, HeaderFormat};
use super::util::from_one_raw_str; use super::util::from_one_raw_str;
/// The `Content-Length` header. /// The `Content-Length` header.
@@ -17,7 +17,9 @@ impl Header for ContentLength {
fn parse_header(raw: &[Vec<u8>]) -> Option<ContentLength> { fn parse_header(raw: &[Vec<u8>]) -> Option<ContentLength> {
from_one_raw_str(raw).map(|u| ContentLength(u)) from_one_raw_str(raw).map(|u| ContentLength(u))
} }
}
impl HeaderFormat for ContentLength {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let ContentLength(ref value) = *self; let ContentLength(ref value) = *self;
value.fmt(fmt) value.fmt(fmt)

View File

@@ -1,4 +1,4 @@
use header::Header; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{mod, Show};
use super::util::from_one_raw_str; use super::util::from_one_raw_str;
use mime::Mime; use mime::Mime;
@@ -18,7 +18,9 @@ impl Header for ContentType {
fn parse_header(raw: &[Vec<u8>]) -> Option<ContentType> { fn parse_header(raw: &[Vec<u8>]) -> Option<ContentType> {
from_one_raw_str(raw).map(|mime| ContentType(mime)) from_one_raw_str(raw).map(|mime| ContentType(mime))
} }
}
impl HeaderFormat for ContentType {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let ContentType(ref value) = *self; let ContentType(ref value) = *self;
value.fmt(fmt) value.fmt(fmt)

View File

@@ -1,4 +1,4 @@
use header::Header; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{mod, Show};
use super::util::from_one_raw_str; use super::util::from_one_raw_str;
use std::from_str::FromStr; use std::from_str::FromStr;
@@ -17,7 +17,9 @@ impl Header for Date {
fn parse_header(raw: &[Vec<u8>]) -> Option<Date> { fn parse_header(raw: &[Vec<u8>]) -> Option<Date> {
from_one_raw_str(raw) from_one_raw_str(raw)
} }
}
impl HeaderFormat for Date {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.fmt(fmt) self.fmt(fmt)
} }

View File

@@ -1,4 +1,4 @@
use header::Header; use header::{Header, HeaderFormat};
use Port; use Port;
use std::fmt::{mod, Show}; use std::fmt::{mod, Show};
use super::util::from_one_raw_str; use super::util::from_one_raw_str;
@@ -61,7 +61,9 @@ impl Header for Host {
}) })
}) })
} }
}
impl HeaderFormat for Host {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self.port { match self.port {
None | Some(80) | Some(443) => self.hostname.fmt(fmt), None | Some(80) | Some(443) => self.hostname.fmt(fmt),

View File

@@ -1,4 +1,4 @@
use header::Header; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{mod, Show};
use super::util::from_one_raw_str; use super::util::from_one_raw_str;
@@ -24,7 +24,9 @@ impl Header for Location {
fn parse_header(raw: &[Vec<u8>]) -> Option<Location> { fn parse_header(raw: &[Vec<u8>]) -> Option<Location> {
from_one_raw_str(raw).map(|s| Location(s)) from_one_raw_str(raw).map(|s| Location(s))
} }
}
impl HeaderFormat for Location {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let Location(ref value) = *self; let Location(ref value) = *self;
value.fmt(fmt) value.fmt(fmt)

View File

@@ -1,4 +1,4 @@
use header::Header; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{mod, Show};
use super::util::from_one_raw_str; use super::util::from_one_raw_str;
@@ -16,7 +16,9 @@ impl Header for Server {
fn parse_header(raw: &[Vec<u8>]) -> Option<Server> { fn parse_header(raw: &[Vec<u8>]) -> Option<Server> {
from_one_raw_str(raw).map(|s| Server(s)) from_one_raw_str(raw).map(|s| Server(s))
} }
}
impl HeaderFormat for Server {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let Server(ref value) = *self; let Server(ref value) = *self;
value.fmt(fmt) value.fmt(fmt)

View File

@@ -1,4 +1,4 @@
use header::Header; use header::{Header, HeaderFormat};
use std::fmt; use std::fmt;
use std::from_str::FromStr; use std::from_str::FromStr;
use super::{from_comma_delimited, fmt_comma_delimited}; use super::{from_comma_delimited, fmt_comma_delimited};
@@ -75,7 +75,9 @@ impl Header for TransferEncoding {
fn parse_header(raw: &[Vec<u8>]) -> Option<TransferEncoding> { fn parse_header(raw: &[Vec<u8>]) -> Option<TransferEncoding> {
from_comma_delimited(raw).map(|vec| TransferEncoding(vec)) from_comma_delimited(raw).map(|vec| TransferEncoding(vec))
} }
}
impl HeaderFormat for TransferEncoding {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let TransferEncoding(ref parts) = *self; let TransferEncoding(ref parts) = *self;
fmt_comma_delimited(fmt, parts[]) fmt_comma_delimited(fmt, parts[])

View File

@@ -1,4 +1,4 @@
use header::Header; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{mod, Show};
use super::{from_comma_delimited, fmt_comma_delimited}; use super::{from_comma_delimited, fmt_comma_delimited};
use std::from_str::FromStr; use std::from_str::FromStr;
@@ -42,7 +42,9 @@ impl Header for Upgrade {
fn parse_header(raw: &[Vec<u8>]) -> Option<Upgrade> { fn parse_header(raw: &[Vec<u8>]) -> Option<Upgrade> {
from_comma_delimited(raw).map(|vec| Upgrade(vec)) from_comma_delimited(raw).map(|vec| Upgrade(vec))
} }
}
impl HeaderFormat for Upgrade {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let Upgrade(ref parts) = *self; let Upgrade(ref parts) = *self;
fmt_comma_delimited(fmt, parts[]) fmt_comma_delimited(fmt, parts[])

View File

@@ -1,4 +1,4 @@
use header::Header; use header::{Header, HeaderFormat};
use std::fmt::{mod, Show}; use std::fmt::{mod, Show};
use super::util::from_one_raw_str; use super::util::from_one_raw_str;
@@ -16,7 +16,9 @@ impl Header for UserAgent {
fn parse_header(raw: &[Vec<u8>]) -> Option<UserAgent> { fn parse_header(raw: &[Vec<u8>]) -> Option<UserAgent> {
from_one_raw_str(raw).map(|s| UserAgent(s)) from_one_raw_str(raw).map(|s| UserAgent(s))
} }
}
impl HeaderFormat for UserAgent {
fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let UserAgent(ref value) = *self; let UserAgent(ref value) = *self;
value.fmt(fmt) value.fmt(fmt)

View File

@@ -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)