blob: 939278643b413aa54cacab10f8354ccb63f7c1a7 [file] [log] [blame]
Allen George8b96bfb2016-11-02 08:01:08 -04001// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
Allen George0e22c362017-01-30 07:15:00 -050018//! Types used to send and receive bytes over an I/O channel.
Allen George8b96bfb2016-11-02 08:01:08 -040019//!
Allen George0e22c362017-01-30 07:15:00 -050020//! The core types are the `TReadTransport`, `TWriteTransport` and the
21//! `TIoChannel` traits, through which `TInputProtocol` or
22//! `TOutputProtocol` can receive and send primitives over the wire. While
23//! `TInputProtocol` and `TOutputProtocol` instances deal with language primitives
24//! the types in this module understand only bytes.
Allen George8b96bfb2016-11-02 08:01:08 -040025
Allen George8b96bfb2016-11-02 08:01:08 -040026use std::io;
Allen George0e22c362017-01-30 07:15:00 -050027use std::io::{Read, Write};
28use std::ops::{Deref, DerefMut};
29
30#[cfg(test)]
31macro_rules! assert_eq_transport_num_written_bytes {
32 ($transport:ident, $num_written_bytes:expr) => {
33 {
34 assert_eq!($transport.channel.write_bytes().len(), $num_written_bytes);
35 }
36 };
37}
38
39
40#[cfg(test)]
41macro_rules! assert_eq_transport_written_bytes {
42 ($transport:ident, $expected_bytes:ident) => {
43 {
44 assert_eq!($transport.channel.write_bytes(), &$expected_bytes);
45 }
46 };
47}
Allen George8b96bfb2016-11-02 08:01:08 -040048
49mod buffered;
50mod framed;
Allen George8b96bfb2016-11-02 08:01:08 -040051mod socket;
Allen George0e22c362017-01-30 07:15:00 -050052mod mem;
Allen George8b96bfb2016-11-02 08:01:08 -040053
Allen George0e22c362017-01-30 07:15:00 -050054pub use self::buffered::{TBufferedReadTransport, TBufferedReadTransportFactory,
55 TBufferedWriteTransport, TBufferedWriteTransportFactory};
56pub use self::framed::{TFramedReadTransport, TFramedReadTransportFactory, TFramedWriteTransport,
57 TFramedWriteTransportFactory};
58pub use self::mem::TBufferChannel;
59pub use self::socket::TTcpChannel;
Allen George8b96bfb2016-11-02 08:01:08 -040060
Allen George0e22c362017-01-30 07:15:00 -050061/// Identifies a transport used by a `TInputProtocol` to receive bytes.
62pub trait TReadTransport: Read {}
Allen George8b96bfb2016-11-02 08:01:08 -040063
Allen George0e22c362017-01-30 07:15:00 -050064/// Helper type used by a server to create `TReadTransport` instances for
65/// accepted client connections.
66pub trait TReadTransportFactory {
67 /// Create a `TTransport` that wraps a channel over which bytes are to be read.
68 fn create(&self, channel: Box<Read + Send>) -> Box<TReadTransport + Send>;
69}
Allen George8b96bfb2016-11-02 08:01:08 -040070
Allen George0e22c362017-01-30 07:15:00 -050071/// Identifies a transport used by `TOutputProtocol` to send bytes.
72pub trait TWriteTransport: Write {}
73
74/// Helper type used by a server to create `TWriteTransport` instances for
75/// accepted client connections.
76pub trait TWriteTransportFactory {
77 /// Create a `TTransport` that wraps a channel over which bytes are to be sent.
78 fn create(&self, channel: Box<Write + Send>) -> Box<TWriteTransport + Send>;
79}
80
81impl<T> TReadTransport for T
82where
83 T: Read,
84{
85}
86
87impl<T> TWriteTransport for T
88where
89 T: Write,
90{
91}
92
93// FIXME: implement the Debug trait for boxed transports
94
95impl<T> TReadTransportFactory for Box<T>
96where
97 T: TReadTransportFactory + ?Sized,
98{
99 fn create(&self, channel: Box<Read + Send>) -> Box<TReadTransport + Send> {
100 (**self).create(channel)
101 }
102}
103
104impl<T> TWriteTransportFactory for Box<T>
105where
106 T: TWriteTransportFactory + ?Sized,
107{
108 fn create(&self, channel: Box<Write + Send>) -> Box<TWriteTransport + Send> {
109 (**self).create(channel)
110 }
111}
112
113/// Identifies a splittable bidirectional I/O channel used to send and receive bytes.
114pub trait TIoChannel: Read + Write {
115 /// Split the channel into a readable half and a writable half, where the
116 /// readable half implements `io::Read` and the writable half implements
117 /// `io::Write`. Returns `None` if the channel was not initialized, or if it
118 /// cannot be split safely.
119 ///
120 /// Returned halves may share the underlying OS channel or buffer resources.
121 /// Implementations **should ensure** that these two halves can be safely
122 /// used independently by concurrent threads.
123 fn split(self) -> ::Result<(::transport::ReadHalf<Self>, ::transport::WriteHalf<Self>)>
124 where
125 Self: Sized;
126}
127
128/// The readable half of an object returned from `TIoChannel::split`.
129#[derive(Debug)]
130pub struct ReadHalf<C>
131where
132 C: Read,
133{
134 handle: C,
135}
136
137/// The writable half of an object returned from `TIoChannel::split`.
138#[derive(Debug)]
139pub struct WriteHalf<C>
140where
141 C: Write,
142{
143 handle: C,
144}
145
146impl<C> Read for ReadHalf<C>
147where
148 C: Read,
149{
150 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
151 self.handle.read(buf)
152 }
153}
154
155impl<C> Write for WriteHalf<C>
156where
157 C: Write,
158{
159 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
160 self.handle.write(buf)
161 }
162
163 fn flush(&mut self) -> io::Result<()> {
164 self.handle.flush()
165 }
166}
167
168impl<C> Deref for ReadHalf<C>
169where
170 C: Read,
171{
172 type Target = C;
173
174 fn deref(&self) -> &Self::Target {
175 &self.handle
176 }
177}
178
179impl<C> DerefMut for ReadHalf<C>
180where
181 C: Read,
182{
183 fn deref_mut(&mut self) -> &mut C {
184 &mut self.handle
185 }
186}
187
188impl<C> Deref for WriteHalf<C>
189where
190 C: Write,
191{
192 type Target = C;
193
194 fn deref(&self) -> &Self::Target {
195 &self.handle
196 }
197}
198
199impl<C> DerefMut for WriteHalf<C>
200where
201 C: Write,
202{
203 fn deref_mut(&mut self) -> &mut C {
204 &mut self.handle
205 }
206}
207
208#[cfg(test)]
209mod tests {
210
211 use std::io::Cursor;
212
213 use super::*;
214
215 #[test]
216 fn must_create_usable_read_channel_from_concrete_read_type() {
217 let r = Cursor::new([0, 1, 2]);
218 let _ = TBufferedReadTransport::new(r);
219 }
220
221 #[test]
222 fn must_create_usable_read_channel_from_boxed_read() {
223 let r: Box<Read> = Box::new(Cursor::new([0, 1, 2]));
224 let _ = TBufferedReadTransport::new(r);
225 }
226
227 #[test]
228 fn must_create_usable_write_channel_from_concrete_write_type() {
229 let w = vec![0u8; 10];
230 let _ = TBufferedWriteTransport::new(w);
231 }
232
233 #[test]
234 fn must_create_usable_write_channel_from_boxed_write() {
235 let w: Box<Write> = Box::new(vec![0u8; 10]);
236 let _ = TBufferedWriteTransport::new(w);
237 }
238
239 #[test]
240 fn must_create_usable_read_transport_from_concrete_read_transport() {
241 let r = Cursor::new([0, 1, 2]);
242 let mut t = TBufferedReadTransport::new(r);
243 takes_read_transport(&mut t)
244 }
245
246 #[test]
247 fn must_create_usable_read_transport_from_boxed_read() {
248 let r = Cursor::new([0, 1, 2]);
249 let mut t: Box<TReadTransport> = Box::new(TBufferedReadTransport::new(r));
250 takes_read_transport(&mut t)
251 }
252
253 #[test]
254 fn must_create_usable_write_transport_from_concrete_write_transport() {
255 let w = vec![0u8; 10];
256 let mut t = TBufferedWriteTransport::new(w);
257 takes_write_transport(&mut t)
258 }
259
260 #[test]
261 fn must_create_usable_write_transport_from_boxed_write() {
262 let w = vec![0u8; 10];
263 let mut t: Box<TWriteTransport> = Box::new(TBufferedWriteTransport::new(w));
264 takes_write_transport(&mut t)
265 }
266
267 fn takes_read_transport<R>(t: &mut R)
268 where
269 R: TReadTransport,
270 {
271 t.bytes();
272 }
273
274 fn takes_write_transport<W>(t: &mut W)
275 where
276 W: TWriteTransport,
277 {
278 t.flush().unwrap();
279 }
Allen George8b96bfb2016-11-02 08:01:08 -0400280}