Skip to content

Commit 22ce3ba

Browse files
committed
Use trait objects and dynamic dispatch to abstract over NetworkStream
Server and client benchmarks show that this makes very little difference in performance and using dynamic dispatch here is significantly more ergonomic. This also bounds NetworkStream with Send to prevent incorrect implementations. Allows the implementation of mock streams for testing and flexibility. Fixes #5
1 parent 0285fc2 commit 22ce3ba

File tree

4 files changed

+31
-17
lines changed

4 files changed

+31
-17
lines changed

examples/concurrent-server.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use hyper::header::common::ContentLength;
1313
use hyper::net::{HttpStream, HttpAcceptor};
1414

1515
trait ConcurrentHandler: Send + Sync {
16-
fn handle(&self, req: Request, res: Response<Fresh, HttpStream>);
16+
fn handle(&self, req: Request, res: Response<Fresh>);
1717
}
1818

1919
struct Concurrent<H: ConcurrentHandler> { handler: Arc<H> }
@@ -39,7 +39,7 @@ macro_rules! try_abort(
3939
struct Echo;
4040

4141
impl ConcurrentHandler for Echo {
42-
fn handle(&self, mut req: Request, mut res: Response<Fresh, HttpStream>) {
42+
fn handle(&self, mut req: Request, mut res: Response<Fresh>) {
4343
match req.uri {
4444
hyper::uri::AbsolutePath(ref path) => match (&req.method, path.as_slice()) {
4545
(&Get, "/") | (&Get, "/echo") => {

src/net.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,27 @@ pub trait NetworkAcceptor<S: NetworkStream>: Acceptor<S> + Clone + Send {
2222
}
2323

2424
/// An abstraction over streams that a Server can utilize.
25-
pub trait NetworkStream: Stream + Clone {
25+
pub trait NetworkStream: Stream + Clone + Send {
2626
/// Get the remote address of the underlying connection.
2727
fn peer_name(&mut self) -> IoResult<SocketAddr>;
2828

2929
/// Connect to a remote address.
3030
fn connect(host: &str, port: Port) -> IoResult<Self>;
3131
}
3232

33+
impl Reader for Box<NetworkStream + Send> {
34+
#[inline]
35+
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) }
36+
}
37+
38+
impl Writer for Box<NetworkStream + Send> {
39+
#[inline]
40+
fn write(&mut self, msg: &[u8]) -> IoResult<()> { self.write(msg) }
41+
42+
#[inline]
43+
fn flush(&mut self) -> IoResult<()> { self.flush() }
44+
}
45+
3346
/// A `NetworkListener` for `HttpStream`s.
3447
pub struct HttpListener {
3548
inner: TcpListener

src/server/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ pub struct Incoming<'a, A: 'a = HttpAcceptor> {
6666
from: IncomingConnections<'a, A>
6767
}
6868

69-
impl<'a, A: NetworkAcceptor<S>, S: NetworkStream> Iterator<(Request<S>, Response<Fresh, S>)> for Incoming<'a, A> {
70-
fn next(&mut self) -> Option<(Request<S>, Response<Fresh, S>)> {
69+
impl<'a, A: NetworkAcceptor<S>, S: NetworkStream> Iterator<(Request<S>, Response<Fresh>)> for Incoming<'a, A> {
70+
fn next(&mut self) -> Option<(Request<S>, Response<Fresh>)> {
7171
for conn in self.from {
7272
match conn {
7373
Ok(stream) => {

src/server/response.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,18 @@ impl WriteStatus for Streaming {}
2626
impl WriteStatus for Fresh {}
2727

2828
/// The outgoing half for a Tcp connection, created by a `Server` and given to a `Handler`.
29-
pub struct Response<W: WriteStatus, S: NetworkStream> {
29+
pub struct Response<W: WriteStatus> {
3030
/// The HTTP version of this response.
3131
pub version: version::HttpVersion,
3232
// Stream the Response is writing to, not accessible through UnwrittenResponse
33-
body: BufferedWriter<S>, // TODO: use a HttpWriter from rfc7230
33+
body: BufferedWriter<Box<NetworkStream + Send>>, // TODO: use a HttpWriter from rfc7230
3434
// The status code for the request.
3535
status: status::StatusCode,
3636
// The outgoing headers on this response.
3737
headers: header::Headers
3838
}
3939

40-
impl<W: WriteStatus, S: NetworkStream> Response<W, S> {
40+
impl<W: WriteStatus> Response<W> {
4141
/// The status of this response.
4242
#[inline]
4343
pub fn status(&self) -> status::StatusCode { self.status }
@@ -47,9 +47,9 @@ impl<W: WriteStatus, S: NetworkStream> Response<W, S> {
4747

4848
/// Construct a Response from its constituent parts.
4949
pub fn construct(version: version::HttpVersion,
50-
body: BufferedWriter<S>,
50+
body: BufferedWriter<Box<NetworkStream + Send>>,
5151
status: status::StatusCode,
52-
headers: header::Headers) -> Response<Fresh, S> {
52+
headers: header::Headers) -> Response<Fresh> {
5353
Response {
5454
status: status,
5555
version: version,
@@ -59,19 +59,19 @@ impl<W: WriteStatus, S: NetworkStream> Response<W, S> {
5959
}
6060
}
6161

62-
impl<S: NetworkStream> Response<Fresh, S> {
62+
impl Response<Fresh> {
6363
/// Creates a new Response that can be used to write to a network stream.
64-
pub fn new(stream: S) -> Response<Fresh, S> {
64+
pub fn new<S: NetworkStream>(stream: S) -> Response<Fresh> {
6565
Response {
6666
status: status::Ok,
6767
version: version::Http11,
6868
headers: header::Headers::new(),
69-
body: BufferedWriter::new(stream)
69+
body: BufferedWriter::new(box stream as Box<NetworkStream + Send>)
7070
}
7171
}
7272

7373
/// Consume this Response<Fresh>, writing the Headers and Status and creating a Response<Streaming>
74-
pub fn start(mut self) -> IoResult<Response<Streaming, S>> {
74+
pub fn start(mut self) -> IoResult<Response<Streaming>> {
7575
debug!("writing head: {} {}", self.version, self.status);
7676
try!(write!(self.body, "{} {}{}{}", self.version, self.status, CR as char, LF as char));
7777

@@ -104,20 +104,21 @@ impl<S: NetworkStream> Response<Fresh, S> {
104104
pub fn headers_mut(&mut self) -> &mut header::Headers { &mut self.headers }
105105

106106
/// Deconstruct this Response into its constituent parts.
107-
pub fn deconstruct(self) -> (version::HttpVersion, BufferedWriter<S>, status::StatusCode, header::Headers) {
107+
pub fn deconstruct(self) -> (version::HttpVersion, BufferedWriter<Box<NetworkStream + Send>>,
108+
status::StatusCode, header::Headers) {
108109
(self.version, self.body, self.status, self.headers)
109110
}
110111
}
111112

112-
impl<S: NetworkStream> Response<Streaming, S> {
113+
impl Response<Streaming> {
113114
/// Flushes all writing of a response to the client.
114115
pub fn end(mut self) -> IoResult<()> {
115116
debug!("ending");
116117
self.flush()
117118
}
118119
}
119120

120-
impl<S: NetworkStream> Writer for Response<Streaming, S> {
121+
impl Writer for Response<Streaming> {
121122
fn write(&mut self, msg: &[u8]) -> IoResult<()> {
122123
debug!("write {:u} bytes", msg.len());
123124
self.body.write(msg)

0 commit comments

Comments
 (0)