blob: 6e84bfa492b167677f23339e50544a72fc9b842f [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
Jake W24918ab2018-11-12 12:43:04 +0800146impl<C> ReadHalf<C>
147where
148 C: Read,
149{
150 /// Create a `ReadHalf` associated with readable `handle`
151 pub fn new(handle: C) -> ReadHalf<C> {
152 ReadHalf { handle }
153 }
154}
155
156impl<C> WriteHalf<C>
157where
158 C: Write,
159{
160 /// Create a `WriteHalf` associated with writable `handle`
161 pub fn new(handle: C) -> WriteHalf<C> {
162 WriteHalf { handle }
163 }
164}
165
Allen George0e22c362017-01-30 07:15:00 -0500166impl<C> Read for ReadHalf<C>
167where
168 C: Read,
169{
170 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
171 self.handle.read(buf)
172 }
173}
174
175impl<C> Write for WriteHalf<C>
176where
177 C: Write,
178{
179 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
180 self.handle.write(buf)
181 }
182
183 fn flush(&mut self) -> io::Result<()> {
184 self.handle.flush()
185 }
186}
187
188impl<C> Deref for ReadHalf<C>
189where
190 C: Read,
191{
192 type Target = C;
193
194 fn deref(&self) -> &Self::Target {
195 &self.handle
196 }
197}
198
199impl<C> DerefMut for ReadHalf<C>
200where
201 C: Read,
202{
203 fn deref_mut(&mut self) -> &mut C {
204 &mut self.handle
205 }
206}
207
208impl<C> Deref for WriteHalf<C>
209where
210 C: Write,
211{
212 type Target = C;
213
214 fn deref(&self) -> &Self::Target {
215 &self.handle
216 }
217}
218
219impl<C> DerefMut for WriteHalf<C>
220where
221 C: Write,
222{
223 fn deref_mut(&mut self) -> &mut C {
224 &mut self.handle
225 }
226}
227
228#[cfg(test)]
229mod tests {
230
231 use std::io::Cursor;
232
233 use super::*;
234
235 #[test]
236 fn must_create_usable_read_channel_from_concrete_read_type() {
237 let r = Cursor::new([0, 1, 2]);
238 let _ = TBufferedReadTransport::new(r);
239 }
240
241 #[test]
242 fn must_create_usable_read_channel_from_boxed_read() {
243 let r: Box<Read> = Box::new(Cursor::new([0, 1, 2]));
244 let _ = TBufferedReadTransport::new(r);
245 }
246
247 #[test]
248 fn must_create_usable_write_channel_from_concrete_write_type() {
249 let w = vec![0u8; 10];
250 let _ = TBufferedWriteTransport::new(w);
251 }
252
253 #[test]
254 fn must_create_usable_write_channel_from_boxed_write() {
255 let w: Box<Write> = Box::new(vec![0u8; 10]);
256 let _ = TBufferedWriteTransport::new(w);
257 }
258
259 #[test]
260 fn must_create_usable_read_transport_from_concrete_read_transport() {
261 let r = Cursor::new([0, 1, 2]);
262 let mut t = TBufferedReadTransport::new(r);
263 takes_read_transport(&mut t)
264 }
265
266 #[test]
267 fn must_create_usable_read_transport_from_boxed_read() {
268 let r = Cursor::new([0, 1, 2]);
269 let mut t: Box<TReadTransport> = Box::new(TBufferedReadTransport::new(r));
270 takes_read_transport(&mut t)
271 }
272
273 #[test]
274 fn must_create_usable_write_transport_from_concrete_write_transport() {
275 let w = vec![0u8; 10];
276 let mut t = TBufferedWriteTransport::new(w);
277 takes_write_transport(&mut t)
278 }
279
280 #[test]
281 fn must_create_usable_write_transport_from_boxed_write() {
282 let w = vec![0u8; 10];
283 let mut t: Box<TWriteTransport> = Box::new(TBufferedWriteTransport::new(w));
284 takes_write_transport(&mut t)
285 }
286
287 fn takes_read_transport<R>(t: &mut R)
288 where
289 R: TReadTransport,
290 {
291 t.bytes();
292 }
293
294 fn takes_write_transport<W>(t: &mut W)
295 where
296 W: TWriteTransport,
297 {
298 t.flush().unwrap();
299 }
Allen George8b96bfb2016-11-02 08:01:08 -0400300}