websocket_base/
stream.rs

1//! Provides the default stream type for WebSocket connections.
2
3use std::fmt::Arguments;
4use std::io::{self, Read, Write};
5
6/// Represents a stream that can be read from, and written to.
7/// This is an abstraction around readable and writable things to be able
8/// to speak websockets over ssl, tcp, unix sockets, etc.
9pub trait Stream: Read + Write {}
10impl<S> Stream for S where S: Read + Write {}
11
12/// If you would like to combine an input stream and an output stream into a single
13/// stream to talk websockets over then this is the struct for you!
14///
15/// This is useful if you want to use different mediums for different directions.
16pub struct ReadWritePair<R, W>(pub R, pub W)
17where
18	R: Read,
19	W: Write;
20
21impl<R, W> Read for ReadWritePair<R, W>
22where
23	R: Read,
24	W: Write,
25{
26	#[inline(always)]
27	fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
28		self.0.read(buf)
29	}
30	#[inline(always)]
31	fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
32		self.0.read_to_end(buf)
33	}
34	#[inline(always)]
35	fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
36		self.0.read_to_string(buf)
37	}
38	#[inline(always)]
39	fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
40		self.0.read_exact(buf)
41	}
42}
43
44impl<R, W> Write for ReadWritePair<R, W>
45where
46	R: Read,
47	W: Write,
48{
49	#[inline(always)]
50	fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
51		self.1.write(buf)
52	}
53	#[inline(always)]
54	fn flush(&mut self) -> io::Result<()> {
55		self.1.flush()
56	}
57	#[inline(always)]
58	fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
59		self.1.write_all(buf)
60	}
61	#[inline(always)]
62	fn write_fmt(&mut self, fmt: Arguments) -> io::Result<()> {
63		self.1.write_fmt(fmt)
64	}
65}
66
67/// A collection of traits and implementations for async streams.
68#[cfg(feature = "async")]
69pub mod r#async {
70	pub use super::ReadWritePair;
71	use futures::Poll;
72	use std::io::{self, Read, Write};
73	pub use tokio_io::io::{ReadHalf, WriteHalf};
74	pub use tokio_io::{AsyncRead, AsyncWrite};
75	pub use tokio_tcp::TcpStream;
76
77	/// A stream that can be read from and written to asynchronously.
78	/// This let's us abstract over many async streams like tcp, ssl,
79	/// udp, ssh, etc.
80	pub trait Stream: AsyncRead + AsyncWrite {}
81	impl<S> Stream for S where S: AsyncRead + AsyncWrite {}
82
83	impl<R, W> AsyncRead for ReadWritePair<R, W>
84	where
85		R: AsyncRead,
86		W: Write,
87	{
88	}
89
90	impl<R, W> AsyncWrite for ReadWritePair<R, W>
91	where
92		W: AsyncWrite,
93		R: Read,
94	{
95		fn shutdown(&mut self) -> Poll<(), io::Error> {
96			self.1.shutdown()
97		}
98	}
99}
100
101/// A collection of traits and implementations for synchronous streams.
102#[cfg(feature = "sync")]
103pub mod sync {
104	pub use super::ReadWritePair;
105	#[cfg(feature = "sync-ssl")]
106	pub use native_tls::TlsStream;
107	use std::io::{self, Read, Write};
108	pub use std::net::Shutdown;
109	pub use std::net::TcpStream;
110	use std::ops::Deref;
111
112	pub use super::Stream;
113
114	/// a `Stream` that can also be used as a borrow to a `TcpStream`
115	/// this is useful when you want to set `TcpStream` options on a
116	/// `Stream` like `nonblocking`.
117	pub trait NetworkStream: Read + Write + AsTcpStream {}
118
119	impl<S> NetworkStream for S where S: Read + Write + AsTcpStream {}
120
121	/// some streams can be split up into separate reading and writing components
122	/// `TcpStream` is an example. This trait marks this ability so one can split
123	/// up the client into two parts.
124	///
125	/// Notice however that this is not possible to do with SSL.
126	pub trait Splittable {
127		/// The reading component of this type
128		type Reader: Read;
129		/// The writing component of this type
130		type Writer: Write;
131
132		/// Split apart this type into a reading and writing component.
133		fn split(self) -> io::Result<(Self::Reader, Self::Writer)>;
134	}
135
136	impl<R, W> Splittable for ReadWritePair<R, W>
137	where
138		R: Read,
139		W: Write,
140	{
141		type Reader = R;
142		type Writer = W;
143
144		fn split(self) -> io::Result<(R, W)> {
145			Ok((self.0, self.1))
146		}
147	}
148
149	impl Splittable for TcpStream {
150		type Reader = TcpStream;
151		type Writer = TcpStream;
152
153		fn split(self) -> io::Result<(TcpStream, TcpStream)> {
154			self.try_clone().map(|s| (s, self))
155		}
156	}
157
158	/// The ability access a borrow to an underlying TcpStream,
159	/// so one can set options on the stream such as `nonblocking`.
160	pub trait AsTcpStream {
161		/// Get a borrow of the TcpStream
162		fn as_tcp(&self) -> &TcpStream;
163	}
164
165	impl AsTcpStream for TcpStream {
166		fn as_tcp(&self) -> &TcpStream {
167			self
168		}
169	}
170
171	#[cfg(feature = "sync-ssl")]
172	impl AsTcpStream for TlsStream<TcpStream> {
173		fn as_tcp(&self) -> &TcpStream {
174			self.get_ref()
175		}
176	}
177
178	impl<T> AsTcpStream for Box<T>
179	where
180		T: AsTcpStream + ?Sized,
181	{
182		fn as_tcp(&self) -> &TcpStream {
183			self.deref().as_tcp()
184		}
185	}
186}