Allen George | 8b96bfb | 2016-11-02 08:01:08 -0400 | [diff] [blame] | 1 | // 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 George | 0e22c36 | 2017-01-30 07:15:00 -0500 | [diff] [blame^] | 18 | //! Types used to send and receive bytes over an I/O channel. |
Allen George | 8b96bfb | 2016-11-02 08:01:08 -0400 | [diff] [blame] | 19 | //! |
Allen George | 0e22c36 | 2017-01-30 07:15:00 -0500 | [diff] [blame^] | 20 | //! 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 George | 8b96bfb | 2016-11-02 08:01:08 -0400 | [diff] [blame] | 25 | |
Allen George | 8b96bfb | 2016-11-02 08:01:08 -0400 | [diff] [blame] | 26 | use std::io; |
Allen George | 0e22c36 | 2017-01-30 07:15:00 -0500 | [diff] [blame^] | 27 | use std::io::{Read, Write}; |
| 28 | use std::ops::{Deref, DerefMut}; |
| 29 | |
| 30 | #[cfg(test)] |
| 31 | macro_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)] |
| 41 | macro_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 George | 8b96bfb | 2016-11-02 08:01:08 -0400 | [diff] [blame] | 48 | |
| 49 | mod buffered; |
| 50 | mod framed; |
Allen George | 8b96bfb | 2016-11-02 08:01:08 -0400 | [diff] [blame] | 51 | mod socket; |
Allen George | 0e22c36 | 2017-01-30 07:15:00 -0500 | [diff] [blame^] | 52 | mod mem; |
Allen George | 8b96bfb | 2016-11-02 08:01:08 -0400 | [diff] [blame] | 53 | |
Allen George | 0e22c36 | 2017-01-30 07:15:00 -0500 | [diff] [blame^] | 54 | pub use self::buffered::{TBufferedReadTransport, TBufferedReadTransportFactory, |
| 55 | TBufferedWriteTransport, TBufferedWriteTransportFactory}; |
| 56 | pub use self::framed::{TFramedReadTransport, TFramedReadTransportFactory, TFramedWriteTransport, |
| 57 | TFramedWriteTransportFactory}; |
| 58 | pub use self::mem::TBufferChannel; |
| 59 | pub use self::socket::TTcpChannel; |
Allen George | 8b96bfb | 2016-11-02 08:01:08 -0400 | [diff] [blame] | 60 | |
Allen George | 0e22c36 | 2017-01-30 07:15:00 -0500 | [diff] [blame^] | 61 | /// Identifies a transport used by a `TInputProtocol` to receive bytes. |
| 62 | pub trait TReadTransport: Read {} |
Allen George | 8b96bfb | 2016-11-02 08:01:08 -0400 | [diff] [blame] | 63 | |
Allen George | 0e22c36 | 2017-01-30 07:15:00 -0500 | [diff] [blame^] | 64 | /// Helper type used by a server to create `TReadTransport` instances for |
| 65 | /// accepted client connections. |
| 66 | pub 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 George | 8b96bfb | 2016-11-02 08:01:08 -0400 | [diff] [blame] | 70 | |
Allen George | 0e22c36 | 2017-01-30 07:15:00 -0500 | [diff] [blame^] | 71 | /// Identifies a transport used by `TOutputProtocol` to send bytes. |
| 72 | pub trait TWriteTransport: Write {} |
| 73 | |
| 74 | /// Helper type used by a server to create `TWriteTransport` instances for |
| 75 | /// accepted client connections. |
| 76 | pub 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 | |
| 81 | impl<T> TReadTransport for T |
| 82 | where |
| 83 | T: Read, |
| 84 | { |
| 85 | } |
| 86 | |
| 87 | impl<T> TWriteTransport for T |
| 88 | where |
| 89 | T: Write, |
| 90 | { |
| 91 | } |
| 92 | |
| 93 | // FIXME: implement the Debug trait for boxed transports |
| 94 | |
| 95 | impl<T> TReadTransportFactory for Box<T> |
| 96 | where |
| 97 | T: TReadTransportFactory + ?Sized, |
| 98 | { |
| 99 | fn create(&self, channel: Box<Read + Send>) -> Box<TReadTransport + Send> { |
| 100 | (**self).create(channel) |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | impl<T> TWriteTransportFactory for Box<T> |
| 105 | where |
| 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. |
| 114 | pub 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)] |
| 130 | pub struct ReadHalf<C> |
| 131 | where |
| 132 | C: Read, |
| 133 | { |
| 134 | handle: C, |
| 135 | } |
| 136 | |
| 137 | /// The writable half of an object returned from `TIoChannel::split`. |
| 138 | #[derive(Debug)] |
| 139 | pub struct WriteHalf<C> |
| 140 | where |
| 141 | C: Write, |
| 142 | { |
| 143 | handle: C, |
| 144 | } |
| 145 | |
| 146 | impl<C> Read for ReadHalf<C> |
| 147 | where |
| 148 | C: Read, |
| 149 | { |
| 150 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
| 151 | self.handle.read(buf) |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | impl<C> Write for WriteHalf<C> |
| 156 | where |
| 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 | |
| 168 | impl<C> Deref for ReadHalf<C> |
| 169 | where |
| 170 | C: Read, |
| 171 | { |
| 172 | type Target = C; |
| 173 | |
| 174 | fn deref(&self) -> &Self::Target { |
| 175 | &self.handle |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | impl<C> DerefMut for ReadHalf<C> |
| 180 | where |
| 181 | C: Read, |
| 182 | { |
| 183 | fn deref_mut(&mut self) -> &mut C { |
| 184 | &mut self.handle |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | impl<C> Deref for WriteHalf<C> |
| 189 | where |
| 190 | C: Write, |
| 191 | { |
| 192 | type Target = C; |
| 193 | |
| 194 | fn deref(&self) -> &Self::Target { |
| 195 | &self.handle |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | impl<C> DerefMut for WriteHalf<C> |
| 200 | where |
| 201 | C: Write, |
| 202 | { |
| 203 | fn deref_mut(&mut self) -> &mut C { |
| 204 | &mut self.handle |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | #[cfg(test)] |
| 209 | mod 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 George | 8b96bfb | 2016-11-02 08:01:08 -0400 | [diff] [blame] | 280 | } |