convert to using Cow
This commit is contained in:
		| @@ -95,9 +95,9 @@ impl Reader for Response { | |||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|  |     use std::borrow::Borrowed; | ||||||
|     use std::boxed::BoxAny; |     use std::boxed::BoxAny; | ||||||
|     use std::io::BufferedReader; |     use std::io::BufferedReader; | ||||||
|     use std::str::Slice; |  | ||||||
|  |  | ||||||
|     use header::Headers; |     use header::Headers; | ||||||
|     use http::HttpReader::EofReader; |     use http::HttpReader::EofReader; | ||||||
| @@ -117,7 +117,7 @@ mod tests { | |||||||
|             headers: Headers::new(), |             headers: Headers::new(), | ||||||
|             version: version::HttpVersion::Http11, |             version: version::HttpVersion::Http11, | ||||||
|             body: EofReader(BufferedReader::new(box MockStream::new() as Box<NetworkStream + Send>)), |             body: EofReader(BufferedReader::new(box MockStream::new() as Box<NetworkStream + Send>)), | ||||||
|             status_raw: RawStatus(200, Slice("OK")) |             status_raw: RawStatus(200, Borrowed("OK")) | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         let b = res.into_inner().downcast::<MockStream>().unwrap(); |         let b = res.into_inner().downcast::<MockStream>().unwrap(); | ||||||
|   | |||||||
| @@ -6,10 +6,11 @@ | |||||||
| //! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others. | //! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others. | ||||||
| use std::any::Any; | use std::any::Any; | ||||||
| use std::ascii::{AsciiExt, AsciiCast}; | use std::ascii::{AsciiExt, AsciiCast}; | ||||||
|  | use std::borrow::{Borrowed, Owned}; | ||||||
| use std::fmt::{mod, Show}; | use std::fmt::{mod, Show}; | ||||||
| use std::intrinsics::TypeId; | use std::intrinsics::TypeId; | ||||||
| use std::raw::TraitObject; | use std::raw::TraitObject; | ||||||
| use std::str::{SendStr, Slice, Owned}; | use std::str::SendStr; | ||||||
| use std::collections::HashMap; | use std::collections::HashMap; | ||||||
| use std::collections::hash_map::{Entries, Occupied, Vacant}; | use std::collections::hash_map::{Entries, Occupied, Vacant}; | ||||||
| use std::sync::RWLock; | use std::sync::RWLock; | ||||||
| @@ -95,7 +96,7 @@ fn header_name<T: Header>() -> &'static str { | |||||||
| /// A map of header fields on requests and responses. | /// A map of header fields on requests and responses. | ||||||
| #[deriving(Clone)] | #[deriving(Clone)] | ||||||
| pub struct Headers { | pub struct Headers { | ||||||
|     data: HashMap<CaseInsensitive<SendStr>, RWLock<Item>> |     data: HashMap<CaseInsensitive, RWLock<Item>> | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Headers { | impl Headers { | ||||||
| @@ -136,7 +137,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 + HeaderFormat>(&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(Borrowed(header_name::<H>())), | ||||||
|                          RWLock::new(Item::typed(box value as Box<HeaderFormat + Send + Sync>))); |                          RWLock::new(Item::typed(box value as Box<HeaderFormat + Send + Sync>))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -154,7 +155,7 @@ impl Headers { | |||||||
|     pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> { |     pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> { | ||||||
|         self.data |         self.data | ||||||
|             // FIXME(reem): Find a better way to do this lookup without find_equiv. |             // FIXME(reem): Find a better way to do this lookup without find_equiv. | ||||||
|             .get(&CaseInsensitive(Slice(unsafe { mem::transmute::<&str, &str>(name) }))) |             .get(&CaseInsensitive(Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))) | ||||||
|             .and_then(|item| { |             .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 { | ||||||
| @@ -177,8 +178,8 @@ impl Headers { | |||||||
|     /// # let mut headers = Headers::new(); |     /// # let mut headers = Headers::new(); | ||||||
|     /// headers.set_raw("content-length", vec!["5".as_bytes().to_vec()]); |     /// headers.set_raw("content-length", vec!["5".as_bytes().to_vec()]); | ||||||
|     /// ``` |     /// ``` | ||||||
|     pub fn set_raw<K: IntoMaybeOwned<'static>>(&mut self, name: K, value: Vec<Vec<u8>>) { |     pub fn set_raw<K: IntoCow<'static, String, str>>(&mut self, name: K, value: Vec<Vec<u8>>) { | ||||||
|         self.data.insert(CaseInsensitive(name.into_maybe_owned()), RWLock::new(Item::raw(value))); |         self.data.insert(CaseInsensitive(name.into_cow()), RWLock::new(Item::raw(value))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get a reference to the header field's value, if it exists. |     /// Get a reference to the header field's value, if it exists. | ||||||
| @@ -200,7 +201,7 @@ impl Headers { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_or_parse<H: Header + HeaderFormat>(&self) -> Option<&RWLock<Item>> { |     fn get_or_parse<H: Header + HeaderFormat>(&self) -> Option<&RWLock<Item>> { | ||||||
|         self.data.get(&CaseInsensitive(Slice(header_name::<H>()))).and_then(|item| get_or_parse::<H>(item)) |         self.data.get(&CaseInsensitive(Borrowed(header_name::<H>()))).and_then(|item| get_or_parse::<H>(item)) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Returns a boolean of whether a certain header is in the map. |     /// Returns a boolean of whether a certain header is in the map. | ||||||
| @@ -214,13 +215,13 @@ impl Headers { | |||||||
|     /// let has_type = headers.has::<ContentType>(); |     /// let has_type = headers.has::<ContentType>(); | ||||||
|     /// ``` |     /// ``` | ||||||
|     pub fn has<H: Header + HeaderFormat>(&self) -> bool { |     pub fn has<H: Header + HeaderFormat>(&self) -> bool { | ||||||
|         self.data.contains_key(&CaseInsensitive(Slice(header_name::<H>()))) |         self.data.contains_key(&CaseInsensitive(Borrowed(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 + HeaderFormat>(&mut self) -> bool { |     pub fn remove<H: Header + HeaderFormat>(&mut self) -> bool { | ||||||
|         self.data.remove(&CaseInsensitive(Slice(Header::header_name(None::<H>)))).is_some() |         self.data.remove(&CaseInsensitive(Borrowed(Header::header_name(None::<H>)))).is_some() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Returns an iterator over the header fields. |     /// Returns an iterator over the header fields. | ||||||
| @@ -252,7 +253,7 @@ impl fmt::Show for Headers { | |||||||
|  |  | ||||||
| /// An `Iterator` over the fields in a `Headers` map. | /// An `Iterator` over the fields in a `Headers` map. | ||||||
| pub struct HeadersItems<'a> { | pub struct HeadersItems<'a> { | ||||||
|     inner: Entries<'a, CaseInsensitive<SendStr>, RWLock<Item>> |     inner: Entries<'a, CaseInsensitive, RWLock<Item>> | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a> Iterator<HeaderView<'a>> for HeadersItems<'a> { | impl<'a> Iterator<HeaderView<'a>> for HeadersItems<'a> { | ||||||
| @@ -265,13 +266,13 @@ impl<'a> Iterator<HeaderView<'a>> for HeadersItems<'a> { | |||||||
| } | } | ||||||
|  |  | ||||||
| /// Returned with the `HeadersItems` iterator. | /// Returned with the `HeadersItems` iterator. | ||||||
| pub struct HeaderView<'a>(&'a CaseInsensitive<SendStr>, &'a RWLock<Item>); | pub struct HeaderView<'a>(&'a CaseInsensitive, &'a RWLock<Item>); | ||||||
|  |  | ||||||
| impl<'a> HeaderView<'a> { | impl<'a> HeaderView<'a> { | ||||||
|     /// Check if a HeaderView is a certain Header. |     /// Check if a HeaderView is a certain Header. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn is<H: Header>(&self) -> bool { |     pub fn is<H: Header>(&self) -> bool { | ||||||
|         CaseInsensitive(header_name::<H>().into_maybe_owned()) == *self.0 |         CaseInsensitive(header_name::<H>().into_cow()) == *self.0 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get the Header name as a slice. |     /// Get the Header name as a slice. | ||||||
| @@ -432,10 +433,16 @@ impl fmt::Show for Box<HeaderFormat + Send + Sync> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[deriving(Clone)] | //#[deriving(Clone)] | ||||||
| struct CaseInsensitive<S: Str>(S); | struct CaseInsensitive(SendStr); | ||||||
|  |  | ||||||
| impl<S: Str> Str for CaseInsensitive<S> { | impl Clone for CaseInsensitive { | ||||||
|  |     fn clone(&self) -> CaseInsensitive { | ||||||
|  |         CaseInsensitive((*self.0).clone().into_cow()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Str for CaseInsensitive { | ||||||
|     fn as_slice(&self) -> &str { |     fn as_slice(&self) -> &str { | ||||||
|         let CaseInsensitive(ref s) = *self; |         let CaseInsensitive(ref s) = *self; | ||||||
|         s.as_slice() |         s.as_slice() | ||||||
| @@ -443,29 +450,27 @@ impl<S: Str> Str for CaseInsensitive<S> { | |||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<S: Str> fmt::Show for CaseInsensitive<S> { | impl fmt::Show for CaseInsensitive { | ||||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||||
|         self.as_slice().fmt(fmt) |         self.as_slice().fmt(fmt) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<S: Str> PartialEq for CaseInsensitive<S> { | impl PartialEq for CaseInsensitive { | ||||||
|     fn eq(&self, other: &CaseInsensitive<S>) -> bool { |     fn eq(&self, other: &CaseInsensitive) -> bool { | ||||||
|         self.as_slice().eq_ignore_ascii_case(other.as_slice()) |         self.as_slice().eq_ignore_ascii_case(other.as_slice()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<S: Str> Eq for CaseInsensitive<S> {} | impl Eq for CaseInsensitive {} | ||||||
|  |  | ||||||
| impl<S: Str, S2: Str> Equiv<CaseInsensitive<S2>> for CaseInsensitive<S> { | impl Equiv<CaseInsensitive> for CaseInsensitive { | ||||||
|     fn equiv(&self, other: &CaseInsensitive<S2>) -> bool { |     fn equiv(&self, other: &CaseInsensitive) -> bool { | ||||||
|         let left = CaseInsensitive(self.as_slice()); |         self == other | ||||||
|         let right = CaseInsensitive(other.as_slice()); |  | ||||||
|         left == right |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<S: Str, H: hash::Writer> hash::Hash<H> for CaseInsensitive<S> { | impl<H: hash::Writer> hash::Hash<H> for CaseInsensitive { | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn hash(&self, hasher: &mut H) { |     fn hash(&self, hasher: &mut H) { | ||||||
|         for b in self.as_slice().bytes() { |         for b in self.as_slice().bytes() { | ||||||
| @@ -491,7 +496,7 @@ impl<H: HeaderFormat> Show for HeaderFormatter<H> { | |||||||
| mod tests { | mod tests { | ||||||
|     use std::io::MemReader; |     use std::io::MemReader; | ||||||
|     use std::fmt; |     use std::fmt; | ||||||
|     use std::str::Slice; |     use std::borrow::Borrowed; | ||||||
|     use std::hash::sip::hash; |     use std::hash::sip::hash; | ||||||
|     use mime::{Mime, Text, Plain}; |     use mime::{Mime, Text, Plain}; | ||||||
|     use super::CaseInsensitive; |     use super::CaseInsensitive; | ||||||
| @@ -506,8 +511,8 @@ mod tests { | |||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_case_insensitive() { |     fn test_case_insensitive() { | ||||||
|         let a = CaseInsensitive(Slice("foobar")); |         let a = CaseInsensitive(Borrowed("foobar")); | ||||||
|         let b = CaseInsensitive(Slice("FOOBAR")); |         let b = CaseInsensitive(Borrowed("FOOBAR")); | ||||||
|  |  | ||||||
|         assert_eq!(a, b); |         assert_eq!(a, b); | ||||||
|         assert_eq!(hash(&a), hash(&b)); |         assert_eq!(hash(&a), hash(&b)); | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								src/http.rs
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								src/http.rs
									
									
									
									
									
								
							| @@ -1,9 +1,10 @@ | |||||||
| //! Pieces pertaining to the HTTP message protocol. | //! Pieces pertaining to the HTTP message protocol. | ||||||
|  | use std::borrow::{Borrowed, Owned}; | ||||||
| use std::cmp::min; | use std::cmp::min; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| use std::io::{mod, Reader, IoResult, BufWriter}; | use std::io::{mod, Reader, IoResult, BufWriter}; | ||||||
| use std::num::from_u16; | use std::num::from_u16; | ||||||
| use std::str::{mod, SendStr, Slice, Owned}; | use std::str::{mod, SendStr}; | ||||||
|  |  | ||||||
| use url::Url; | use url::Url; | ||||||
|  |  | ||||||
| @@ -559,9 +560,15 @@ pub fn read_request_line<R: Reader>(stream: &mut R) -> HttpResult<RequestLine> { | |||||||
| pub type StatusLine = (HttpVersion, RawStatus); | pub type StatusLine = (HttpVersion, RawStatus); | ||||||
|  |  | ||||||
| /// The raw status code and reason-phrase. | /// The raw status code and reason-phrase. | ||||||
| #[deriving(PartialEq, Show, Clone)] | #[deriving(PartialEq, Show)] | ||||||
| pub struct RawStatus(pub u16, pub SendStr); | pub struct RawStatus(pub u16, pub SendStr); | ||||||
|  |  | ||||||
|  | impl Clone for RawStatus { | ||||||
|  |     fn clone(&self) -> RawStatus { | ||||||
|  |         RawStatus(self.0, (*self.1).clone().into_cow()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /// Read the StatusLine, such as `HTTP/1.1 200 OK`. | /// Read the StatusLine, such as `HTTP/1.1 200 OK`. | ||||||
| /// | /// | ||||||
| /// > The first line of a response message is the status-line, consisting | /// > The first line of a response message is the status-line, consisting | ||||||
| @@ -632,7 +639,7 @@ pub fn read_status<R: Reader>(stream: &mut R) -> HttpResult<RawStatus> { | |||||||
|         Some(status) => match status.canonical_reason() { |         Some(status) => match status.canonical_reason() { | ||||||
|             Some(phrase) => { |             Some(phrase) => { | ||||||
|                 if phrase == reason { |                 if phrase == reason { | ||||||
|                     Slice(phrase) |                     Borrowed(phrase) | ||||||
|                 } else { |                 } else { | ||||||
|                     Owned(reason.into_string()) |                     Owned(reason.into_string()) | ||||||
|                 } |                 } | ||||||
| @@ -657,7 +664,7 @@ fn expect(r: IoResult<u8>, expected: u8) -> HttpResult<()> { | |||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     use std::io::{mod, MemReader, MemWriter}; |     use std::io::{mod, MemReader, MemWriter}; | ||||||
|     use std::str::{Slice, Owned}; |     use std::borrow::{Borrowed, Owned}; | ||||||
|     use test::Bencher; |     use test::Bencher; | ||||||
|     use uri::RequestUri; |     use uri::RequestUri; | ||||||
|     use uri::RequestUri::{Star, AbsoluteUri, AbsolutePath, Authority}; |     use uri::RequestUri::{Star, AbsoluteUri, AbsolutePath, Authority}; | ||||||
| @@ -727,8 +734,8 @@ mod tests { | |||||||
|             assert_eq!(read_status(&mut mem(s)), result); |             assert_eq!(read_status(&mut mem(s)), result); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         read("200 OK\r\n", Ok(RawStatus(200, Slice("OK")))); |         read("200 OK\r\n", Ok(RawStatus(200, Borrowed("OK")))); | ||||||
|         read("404 Not Found\r\n", Ok(RawStatus(404, Slice("Not Found")))); |         read("404 Not Found\r\n", Ok(RawStatus(404, Borrowed("Not Found")))); | ||||||
|         read("200 crazy pants\r\n", Ok(RawStatus(200, Owned("crazy pants".to_string())))); |         read("200 crazy pants\r\n", Ok(RawStatus(200, Owned("crazy pants".to_string())))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -774,7 +781,7 @@ mod tests { | |||||||
|     #[bench] |     #[bench] | ||||||
|     fn bench_read_status(b: &mut Bencher) { |     fn bench_read_status(b: &mut Bencher) { | ||||||
|         b.bytes = b"404 Not Found\r\n".len() as u64; |         b.bytes = b"404 Not Found\r\n".len() as u64; | ||||||
|         b.iter(|| assert_eq!(read_status(&mut mem("404 Not Found\r\n")), Ok(RawStatus(404, Slice("Not Found"))))); |         b.iter(|| assert_eq!(read_status(&mut mem("404 Not Found\r\n")), Ok(RawStatus(404, Borrowed("Not Found"))))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user