Use dynamic dispatch for client Request and Response through Box<NetworkStream>

Also adds a convenience `abstract` method to NetworkStream for creating
Box<NetworkStream + Send> from a NetworkStream.
This commit is contained in:
Jonathan Reem
2014-09-09 16:51:32 -07:00
parent 8026867334
commit ed491655dd
5 changed files with 31 additions and 15 deletions

View File

@@ -14,7 +14,7 @@ use super::{Response};
/// A client request to a remote server. /// A client request to a remote server.
pub struct Request<S = HttpStream> { pub struct Request {
/// The method of this request. /// The method of this request.
pub method: method::Method, pub method: method::Method,
/// The headers that will be sent with this request. /// The headers that will be sent with this request.
@@ -24,13 +24,13 @@ pub struct Request<S = HttpStream> {
/// The HTTP version of this request. /// The HTTP version of this request.
pub version: version::HttpVersion, pub version: version::HttpVersion,
headers_written: bool, headers_written: bool,
body: BufferedWriter<S>, body: BufferedWriter<Box<NetworkStream + Send>>,
} }
impl<S: NetworkStream> Request<S> { impl Request {
/// Create a new client request. /// Create a new client request.
pub fn new(method: method::Method, url: Url) -> HttpResult<Request<S>> { pub fn new(method: method::Method, url: Url) -> HttpResult<Request> {
debug!("{} {}", method, url); debug!("{} {}", method, url);
let host = match url.serialize_host() { let host = match url.serialize_host() {
Some(host) => host, Some(host) => host,
@@ -43,8 +43,8 @@ impl<S: NetworkStream> Request<S> {
}; };
debug!("port={}", port); debug!("port={}", port);
let stream = try_io!(NetworkStream::connect(host.as_slice(), port)); let stream: HttpStream = try_io!(NetworkStream::connect(host.as_slice(), port));
let stream = BufferedWriter::new(stream); let stream = BufferedWriter::new(stream.abstract());
let mut headers = Headers::new(); let mut headers = Headers::new();
headers.set(Host(host)); headers.set(Host(host));
Ok(Request { Ok(Request {
@@ -82,7 +82,7 @@ impl<S: NetworkStream> Request<S> {
/// Completes writing the request, and returns a response to read from. /// Completes writing the request, and returns a response to read from.
/// ///
/// Consumes the Request. /// Consumes the Request.
pub fn send(mut self) -> HttpResult<Response<S>> { pub fn send(mut self) -> HttpResult<Response> {
try_io!(self.flush()); try_io!(self.flush());
let raw = self.body.unwrap(); let raw = self.body.unwrap();
Response::new(raw) Response::new(raw)
@@ -90,7 +90,7 @@ impl<S: NetworkStream> Request<S> {
} }
impl<S: NetworkStream> Writer for Request<S> { impl Writer for Request {
fn write(&mut self, msg: &[u8]) -> IoResult<()> { fn write(&mut self, msg: &[u8]) -> IoResult<()> {
if !self.headers_written { if !self.headers_written {
try!(self.write_head()); try!(self.write_head());

View File

@@ -18,14 +18,14 @@ pub struct Response<S = HttpStream> {
pub headers: header::Headers, pub headers: header::Headers,
/// The HTTP version of this response from the server. /// The HTTP version of this response from the server.
pub version: version::HttpVersion, pub version: version::HttpVersion,
body: HttpReader<BufferedReader<S>>, body: HttpReader<BufferedReader<Box<NetworkStream + Send>>>,
} }
impl<S: NetworkStream> Response<S> { impl Response {
/// Creates a new response from a server. /// Creates a new response from a server.
pub fn new(stream: S) -> HttpResult<Response<S>> { pub fn new(stream: Box<NetworkStream + Send>) -> HttpResult<Response> {
let mut stream = BufferedReader::new(stream); let mut stream = BufferedReader::new(stream.abstract());
let (version, status) = try!(read_status_line(&mut stream)); let (version, status) = try!(read_status_line(&mut stream));
let mut headers = try!(header::Headers::from_raw(&mut stream)); let mut headers = try!(header::Headers::from_raw(&mut stream));
@@ -67,7 +67,7 @@ impl<S: NetworkStream> Response<S> {
} }
} }
impl<S: NetworkStream> Reader for Response<S> { impl Reader for Response {
#[inline] #[inline]
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
self.body.read(buf) self.body.read(buf)

View File

@@ -28,6 +28,22 @@ pub trait NetworkStream: Stream + Clone + Send {
/// Connect to a remote address. /// Connect to a remote address.
fn connect(host: &str, port: Port) -> IoResult<Self>; fn connect(host: &str, port: Port) -> IoResult<Self>;
/// Turn this into an appropriately typed trait object.
#[inline]
fn abstract(self) -> Box<NetworkStream + Send> {
box self as Box<NetworkStream + Send>
}
#[doc(hidden)]
#[inline]
// Hack to work around lack of Clone impl for Box<Clone>
fn clone_box(&self) -> Box<NetworkStream + Send> { self.clone().abstract() }
}
impl Clone for Box<NetworkStream + Send> {
#[inline]
fn clone(&self) -> Box<NetworkStream + Send> { self.clone_box() }
} }
impl Reader for Box<NetworkStream + Send> { impl Reader for Box<NetworkStream + Send> {

View File

@@ -37,7 +37,7 @@ impl Request {
/// immediately useful. /// immediately useful.
pub fn new<S: NetworkStream>(mut stream: S) -> HttpResult<Request> { pub fn new<S: NetworkStream>(mut stream: S) -> HttpResult<Request> {
let remote_addr = try_io!(stream.peer_name()); let remote_addr = try_io!(stream.peer_name());
let mut stream = BufferedReader::new(box stream as Box<NetworkStream + Send>); let mut stream = BufferedReader::new(stream.abstract());
let (method, uri, version) = try!(read_request_line(&mut stream)); let (method, uri, version) = try!(read_request_line(&mut stream));
let mut headers = try!(Headers::from_raw(&mut stream)); let mut headers = try!(Headers::from_raw(&mut stream));

View File

@@ -66,7 +66,7 @@ impl Response<Fresh> {
status: status::Ok, status: status::Ok,
version: version::Http11, version: version::Http11,
headers: header::Headers::new(), headers: header::Headers::new(),
body: BufferedWriter::new(box stream as Box<NetworkStream + Send>) body: BufferedWriter::new(stream.abstract())
} }
} }