Skip to content

Rustup #153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 27, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/client/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ impl Request<Streaming> {
///
/// Consumes the Request.
pub fn send(self) -> HttpResult<Response> {
let raw = try!(self.body.end()).unwrap();
let raw = try!(self.body.end()).into_inner();
Response::new(raw)
}
}
Expand Down Expand Up @@ -219,8 +219,8 @@ mod tests {
Get, Url::parse("http://example.dom").unwrap()
).unwrap();
let req = req.start().unwrap();
let stream = *req.body.end().unwrap().unwrap().downcast::<MockStream>().unwrap();
let bytes = stream.write.unwrap();
let stream = *req.body.end().unwrap().into_inner().downcast::<MockStream>().unwrap();
let bytes = stream.write.into_inner();
let s = from_utf8(bytes[]).unwrap();
assert!(!s.contains("Content-Length:"));
assert!(!s.contains("Transfer-Encoding:"));
Expand All @@ -232,8 +232,8 @@ mod tests {
Head, Url::parse("http://example.dom").unwrap()
).unwrap();
let req = req.start().unwrap();
let stream = *req.body.end().unwrap().unwrap().downcast::<MockStream>().unwrap();
let bytes = stream.write.unwrap();
let stream = *req.body.end().unwrap().into_inner().downcast::<MockStream>().unwrap();
let bytes = stream.write.into_inner();
let s = from_utf8(bytes[]).unwrap();
assert!(!s.contains("Content-Length:"));
assert!(!s.contains("Transfer-Encoding:"));
Expand Down
12 changes: 6 additions & 6 deletions src/client/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ impl Response {
&self.status_raw
}

/// Unwraps the Request to return the NetworkStream underneath.
pub fn unwrap(self) -> Box<NetworkStream + Send> {
self.body.unwrap().unwrap()
/// Consumes the Request to return the NetworkStream underneath.
pub fn into_inner(self) -> Box<NetworkStream + Send> {
self.body.unwrap().into_inner()
}
}

Expand All @@ -95,9 +95,9 @@ impl Reader for Response {

#[cfg(test)]
mod tests {
use std::borrow::Borrowed;
use std::boxed::BoxAny;
use std::io::BufferedReader;
use std::str::Slice;

use header::Headers;
use http::HttpReader::EofReader;
Expand All @@ -117,10 +117,10 @@ mod tests {
headers: Headers::new(),
version: version::HttpVersion::Http11,
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.unwrap().downcast::<MockStream>().unwrap();
let b = res.into_inner().downcast::<MockStream>().unwrap();
assert_eq!(b, box MockStream::new());

}
Expand Down
61 changes: 33 additions & 28 deletions src/header/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
//! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others.
use std::any::Any;
use std::ascii::{AsciiExt, AsciiCast};
use std::borrow::{Borrowed, Owned};
use std::fmt::{mod, Show};
use std::intrinsics::TypeId;
use std::raw::TraitObject;
use std::str::{SendStr, Slice, Owned};
use std::str::SendStr;
use std::collections::HashMap;
use std::collections::hash_map::{Entries, Occupied, Vacant};
use std::sync::RWLock;
Expand Down Expand Up @@ -95,7 +96,7 @@ fn header_name<T: Header>() -> &'static str {
/// A map of header fields on requests and responses.
#[deriving(Clone)]
pub struct Headers {
data: HashMap<CaseInsensitive<SendStr>, RWLock<Item>>
data: HashMap<CaseInsensitive, RWLock<Item>>
}

impl Headers {
Expand Down Expand Up @@ -136,7 +137,7 @@ impl Headers {
///
/// The field is determined by the type of the value being set.
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>)));
}

Expand All @@ -154,7 +155,7 @@ impl Headers {
pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> {
self.data
// 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| {
let lock = item.read();
if let Some(ref raw) = lock.raw {
Expand All @@ -177,8 +178,8 @@ impl Headers {
/// # let mut headers = Headers::new();
/// 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>>) {
self.data.insert(CaseInsensitive(name.into_maybe_owned()), RWLock::new(Item::raw(value)));
pub fn set_raw<K: IntoCow<'static, String, str>>(&mut self, name: K, value: Vec<Vec<u8>>) {
self.data.insert(CaseInsensitive(name.into_cow()), RWLock::new(Item::raw(value)));
}

/// Get a reference to the header field's value, if it exists.
Expand All @@ -200,7 +201,7 @@ impl Headers {
}

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.
Expand All @@ -214,13 +215,13 @@ impl Headers {
/// let has_type = headers.has::<ContentType>();
/// ```
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.
/// Returns true if a header has been removed.
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.
Expand Down Expand Up @@ -252,7 +253,7 @@ impl fmt::Show for Headers {

/// An `Iterator` over the fields in a `Headers` map.
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> {
Expand All @@ -265,13 +266,13 @@ impl<'a> Iterator<HeaderView<'a>> for HeadersItems<'a> {
}

/// 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> {
/// Check if a HeaderView is a certain Header.
#[inline]
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.
Expand Down Expand Up @@ -432,40 +433,44 @@ impl fmt::Show for Box<HeaderFormat + Send + Sync> {
}
}

#[deriving(Clone)]
struct CaseInsensitive<S: Str>(S);
//#[deriving(Clone)]
struct CaseInsensitive(SendStr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good simplification. Using IntoCow here in the relevant places is much better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it was only because Cow doesn't yet implement Clone. I've been meaning to pull this into a new crate, and when I do, I'll add the generics back in.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a separate crate it the generic makes a lot of sense.


impl Clone for CaseInsensitive {
fn clone(&self) -> CaseInsensitive {
CaseInsensitive((*self.0).clone().into_cow())
}
}

impl<S: Str> Str for CaseInsensitive<S> {
impl Str for CaseInsensitive {
fn as_slice(&self) -> &str {
let CaseInsensitive(ref s) = *self;
s.as_slice()
}

}

impl<S: Str> fmt::Show for CaseInsensitive<S> {
impl fmt::Show for CaseInsensitive {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.as_slice().fmt(fmt)
}
}

impl<S: Str> PartialEq for CaseInsensitive<S> {
fn eq(&self, other: &CaseInsensitive<S>) -> bool {
impl PartialEq for CaseInsensitive {
fn eq(&self, other: &CaseInsensitive) -> bool {
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> {
fn equiv(&self, other: &CaseInsensitive<S2>) -> bool {
let left = CaseInsensitive(self.as_slice());
let right = CaseInsensitive(other.as_slice());
left == right
impl Equiv<CaseInsensitive> for CaseInsensitive {
fn equiv(&self, other: &CaseInsensitive) -> bool {
self == other
}
}

impl<S: Str, H: hash::Writer> hash::Hash<H> for CaseInsensitive<S> {
impl<H: hash::Writer> hash::Hash<H> for CaseInsensitive {
#[inline]
fn hash(&self, hasher: &mut H) {
for b in self.as_slice().bytes() {
Expand All @@ -491,7 +496,7 @@ impl<H: HeaderFormat> Show for HeaderFormatter<H> {
mod tests {
use std::io::MemReader;
use std::fmt;
use std::str::Slice;
use std::borrow::Borrowed;
use std::hash::sip::hash;
use mime::{Mime, Text, Plain};
use super::CaseInsensitive;
Expand All @@ -506,8 +511,8 @@ mod tests {

#[test]
fn test_case_insensitive() {
let a = CaseInsensitive(Slice("foobar"));
let b = CaseInsensitive(Slice("FOOBAR"));
let a = CaseInsensitive(Borrowed("foobar"));
let b = CaseInsensitive(Borrowed("FOOBAR"));

assert_eq!(a, b);
assert_eq!(hash(&a), hash(&b));
Expand Down
25 changes: 16 additions & 9 deletions src/http.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//! Pieces pertaining to the HTTP message protocol.
use std::borrow::{Borrowed, Owned};
use std::cmp::min;
use std::fmt;
use std::io::{mod, Reader, IoResult, BufWriter};
use std::num::from_u16;
use std::str::{mod, SendStr, Slice, Owned};
use std::str::{mod, SendStr};

use url::Url;

Expand Down Expand Up @@ -559,9 +560,15 @@ pub fn read_request_line<R: Reader>(stream: &mut R) -> HttpResult<RequestLine> {
pub type StatusLine = (HttpVersion, RawStatus);

/// The raw status code and reason-phrase.
#[deriving(PartialEq, Show, Clone)]
#[deriving(PartialEq, Show)]
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`.
///
/// > The first line of a response message is the status-line, consisting
Expand Down Expand Up @@ -632,7 +639,7 @@ pub fn read_status<R: Reader>(stream: &mut R) -> HttpResult<RawStatus> {
Some(status) => match status.canonical_reason() {
Some(phrase) => {
if phrase == reason {
Slice(phrase)
Borrowed(phrase)
} else {
Owned(reason.into_string())
}
Expand All @@ -657,7 +664,7 @@ fn expect(r: IoResult<u8>, expected: u8) -> HttpResult<()> {
#[cfg(test)]
mod tests {
use std::io::{mod, MemReader, MemWriter};
use std::str::{Slice, Owned};
use std::borrow::{Borrowed, Owned};
use test::Bencher;
use uri::RequestUri;
use uri::RequestUri::{Star, AbsoluteUri, AbsolutePath, Authority};
Expand Down Expand Up @@ -727,8 +734,8 @@ mod tests {
assert_eq!(read_status(&mut mem(s)), result);
}

read("200 OK\r\n", Ok(RawStatus(200, Slice("OK"))));
read("404 Not Found\r\n", Ok(RawStatus(404, Slice("Not Found"))));
read("200 OK\r\n", Ok(RawStatus(200, Borrowed("OK"))));
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()))));
}

Expand All @@ -748,7 +755,7 @@ mod tests {
let mut w = super::HttpWriter::ChunkedWriter(MemWriter::new());
w.write(b"foo bar").unwrap();
w.write(b"baz quux herp").unwrap();
let buf = w.end().unwrap().unwrap();
let buf = w.end().unwrap().into_inner();
let s = from_utf8(buf.as_slice()).unwrap();
assert_eq!(s, "7\r\nfoo bar\r\nD\r\nbaz quux herp\r\n0\r\n\r\n");
}
Expand All @@ -760,7 +767,7 @@ mod tests {
w.write(b"foo bar").unwrap();
assert_eq!(w.write(b"baz"), Err(io::standard_error(io::ShortWrite(1))));

let buf = w.end().unwrap().unwrap();
let buf = w.end().unwrap().into_inner();
let s = from_utf8(buf.as_slice()).unwrap();
assert_eq!(s, "foo barb");
}
Expand All @@ -774,7 +781,7 @@ mod tests {
#[bench]
fn bench_read_status(b: &mut Bencher) {
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")))));
}

}