blob: 32c07998a9a470d49882c908fead184d7403f8d3 [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 {
Allen Georgeef7a1892018-12-16 18:01:37 -050032 ($transport:ident, $num_written_bytes:expr) => {{
33 assert_eq!($transport.channel.write_bytes().len(), $num_written_bytes);
34 }};
Allen George0e22c362017-01-30 07:15:00 -050035}
36
Allen George0e22c362017-01-30 07:15:00 -050037#[cfg(test)]
38macro_rules! assert_eq_transport_written_bytes {
Allen Georgeef7a1892018-12-16 18:01:37 -050039 ($transport:ident, $expected_bytes:ident) => {{
40 assert_eq!($transport.channel.write_bytes(), &$expected_bytes);
41 }};
Allen George0e22c362017-01-30 07:15:00 -050042}
Allen George8b96bfb2016-11-02 08:01:08 -040043
44mod buffered;
45mod framed;
Allen George0e22c362017-01-30 07:15:00 -050046mod mem;
Allen Georgeef7a1892018-12-16 18:01:37 -050047mod socket;
Allen George8b96bfb2016-11-02 08:01:08 -040048
Allen Georgeef7a1892018-12-16 18:01:37 -050049pub use self::buffered::{
50 TBufferedReadTransport, TBufferedReadTransportFactory, TBufferedWriteTransport,
51 TBufferedWriteTransportFactory,
52};
53pub use self::framed::{
54 TFramedReadTransport, TFramedReadTransportFactory, TFramedWriteTransport,
55 TFramedWriteTransportFactory,
56};
Allen George0e22c362017-01-30 07:15:00 -050057pub use self::mem::TBufferChannel;
58pub use self::socket::TTcpChannel;
Allen George8b96bfb2016-11-02 08:01:08 -040059
Allen George0e22c362017-01-30 07:15:00 -050060/// Identifies a transport used by a `TInputProtocol` to receive bytes.
61pub trait TReadTransport: Read {}
Allen George8b96bfb2016-11-02 08:01:08 -040062
Allen George0e22c362017-01-30 07:15:00 -050063/// Helper type used by a server to create `TReadTransport` instances for
64/// accepted client connections.
65pub trait TReadTransportFactory {
66 /// Create a `TTransport` that wraps a channel over which bytes are to be read.
Danny Browning77d96c12019-08-21 13:41:07 -060067 fn create(&self, channel: Box<dyn Read + Send>) -> Box<dyn TReadTransport + Send>;
Allen George0e22c362017-01-30 07:15:00 -050068}
Allen George8b96bfb2016-11-02 08:01:08 -040069
Allen George0e22c362017-01-30 07:15:00 -050070/// Identifies a transport used by `TOutputProtocol` to send bytes.
71pub trait TWriteTransport: Write {}
72
73/// Helper type used by a server to create `TWriteTransport` instances for
74/// accepted client connections.
75pub trait TWriteTransportFactory {
76 /// Create a `TTransport` that wraps a channel over which bytes are to be sent.
Danny Browning77d96c12019-08-21 13:41:07 -060077 fn create(&self, channel: Box<dyn Write + Send>) -> Box<dyn TWriteTransport + Send>;
Allen George0e22c362017-01-30 07:15:00 -050078}
79
Allen Georgeef7a1892018-12-16 18:01:37 -050080impl<T> TReadTransport for T where T: Read {}
Allen George0e22c362017-01-30 07:15:00 -050081
Allen Georgeef7a1892018-12-16 18:01:37 -050082impl<T> TWriteTransport for T where T: Write {}
Allen George0e22c362017-01-30 07:15:00 -050083
84// FIXME: implement the Debug trait for boxed transports
85
86impl<T> TReadTransportFactory for Box<T>
87where
88 T: TReadTransportFactory + ?Sized,
89{
Danny Browning77d96c12019-08-21 13:41:07 -060090 fn create(&self, channel: Box<dyn Read + Send>) -> Box<dyn TReadTransport + Send> {
Allen George0e22c362017-01-30 07:15:00 -050091 (**self).create(channel)
92 }
93}
94
95impl<T> TWriteTransportFactory for Box<T>
96where
97 T: TWriteTransportFactory + ?Sized,
98{
Danny Browning77d96c12019-08-21 13:41:07 -060099 fn create(&self, channel: Box<dyn Write + Send>) -> Box<dyn TWriteTransport + Send> {
Allen George0e22c362017-01-30 07:15:00 -0500100 (**self).create(channel)
101 }
102}
103
104/// Identifies a splittable bidirectional I/O channel used to send and receive bytes.
105pub trait TIoChannel: Read + Write {
106 /// Split the channel into a readable half and a writable half, where the
107 /// readable half implements `io::Read` and the writable half implements
108 /// `io::Write`. Returns `None` if the channel was not initialized, or if it
109 /// cannot be split safely.
110 ///
111 /// Returned halves may share the underlying OS channel or buffer resources.
112 /// Implementations **should ensure** that these two halves can be safely
113 /// used independently by concurrent threads.
114 fn split(self) -> ::Result<(::transport::ReadHalf<Self>, ::transport::WriteHalf<Self>)>
115 where
116 Self: Sized;
117}
118
119/// The readable half of an object returned from `TIoChannel::split`.
120#[derive(Debug)]
121pub struct ReadHalf<C>
122where
123 C: Read,
124{
125 handle: C,
126}
127
128/// The writable half of an object returned from `TIoChannel::split`.
129#[derive(Debug)]
130pub struct WriteHalf<C>
131where
132 C: Write,
133{
134 handle: C,
135}
136
Jake W24918ab2018-11-12 12:43:04 +0800137impl<C> ReadHalf<C>
138where
139 C: Read,
140{
141 /// Create a `ReadHalf` associated with readable `handle`
142 pub fn new(handle: C) -> ReadHalf<C> {
143 ReadHalf { handle }
144 }
145}
146
147impl<C> WriteHalf<C>
148where
149 C: Write,
150{
151 /// Create a `WriteHalf` associated with writable `handle`
152 pub fn new(handle: C) -> WriteHalf<C> {
153 WriteHalf { handle }
154 }
155}
156
Allen George0e22c362017-01-30 07:15:00 -0500157impl<C> Read for ReadHalf<C>
158where
159 C: Read,
160{
161 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
162 self.handle.read(buf)
163 }
164}
165
166impl<C> Write for WriteHalf<C>
167where
168 C: Write,
169{
170 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
171 self.handle.write(buf)
172 }
173
174 fn flush(&mut self) -> io::Result<()> {
175 self.handle.flush()
176 }
177}
178
179impl<C> Deref for ReadHalf<C>
180where
181 C: Read,
182{
183 type Target = C;
184
185 fn deref(&self) -> &Self::Target {
186 &self.handle
187 }
188}
189
190impl<C> DerefMut for ReadHalf<C>
191where
192 C: Read,
193{
194 fn deref_mut(&mut self) -> &mut C {
195 &mut self.handle
196 }
197}
198
199impl<C> Deref for WriteHalf<C>
200where
201 C: Write,
202{
203 type Target = C;
204
205 fn deref(&self) -> &Self::Target {
206 &self.handle
207 }
208}
209
210impl<C> DerefMut for WriteHalf<C>
211where
212 C: Write,
213{
214 fn deref_mut(&mut self) -> &mut C {
215 &mut self.handle
216 }
217}
218
219#[cfg(test)]
220mod tests {
221
222 use std::io::Cursor;
223
224 use super::*;
225
226 #[test]
227 fn must_create_usable_read_channel_from_concrete_read_type() {
228 let r = Cursor::new([0, 1, 2]);
229 let _ = TBufferedReadTransport::new(r);
230 }
231
232 #[test]
233 fn must_create_usable_read_channel_from_boxed_read() {
Danny Browning77d96c12019-08-21 13:41:07 -0600234 let r: Box<dyn Read> = Box::new(Cursor::new([0, 1, 2]));
Allen George0e22c362017-01-30 07:15:00 -0500235 let _ = TBufferedReadTransport::new(r);
236 }
237
238 #[test]
239 fn must_create_usable_write_channel_from_concrete_write_type() {
240 let w = vec![0u8; 10];
241 let _ = TBufferedWriteTransport::new(w);
242 }
243
244 #[test]
245 fn must_create_usable_write_channel_from_boxed_write() {
Danny Browning77d96c12019-08-21 13:41:07 -0600246 let w: Box<dyn Write> = Box::new(vec![0u8; 10]);
Allen George0e22c362017-01-30 07:15:00 -0500247 let _ = TBufferedWriteTransport::new(w);
248 }
249
250 #[test]
251 fn must_create_usable_read_transport_from_concrete_read_transport() {
252 let r = Cursor::new([0, 1, 2]);
253 let mut t = TBufferedReadTransport::new(r);
254 takes_read_transport(&mut t)
255 }
256
257 #[test]
258 fn must_create_usable_read_transport_from_boxed_read() {
259 let r = Cursor::new([0, 1, 2]);
Danny Browning77d96c12019-08-21 13:41:07 -0600260 let mut t: Box<dyn TReadTransport> = Box::new(TBufferedReadTransport::new(r));
Allen George0e22c362017-01-30 07:15:00 -0500261 takes_read_transport(&mut t)
262 }
263
264 #[test]
265 fn must_create_usable_write_transport_from_concrete_write_transport() {
266 let w = vec![0u8; 10];
267 let mut t = TBufferedWriteTransport::new(w);
268 takes_write_transport(&mut t)
269 }
270
271 #[test]
272 fn must_create_usable_write_transport_from_boxed_write() {
273 let w = vec![0u8; 10];
Danny Browning77d96c12019-08-21 13:41:07 -0600274 let mut t: Box<dyn TWriteTransport> = Box::new(TBufferedWriteTransport::new(w));
Allen George0e22c362017-01-30 07:15:00 -0500275 takes_write_transport(&mut t)
276 }
277
278 fn takes_read_transport<R>(t: &mut R)
279 where
280 R: TReadTransport,
281 {
282 t.bytes();
283 }
284
285 fn takes_write_transport<W>(t: &mut W)
286 where
287 W: TWriteTransport,
288 {
289 t.flush().unwrap();
290 }
Allen George8b96bfb2016-11-02 08:01:08 -0400291}