THRIFT-4176: Implement threaded server for Rust
Client: rs

* Create a TIoChannel construct
* Separate TTransport into TReadTransport and TWriteTransport
* Restructure types to avoid shared ownership
* Remove user-visible boxing and ref-counting
* Replace TSimpleServer with a thread-pool based TServer

This closes #1255
diff --git a/lib/rs/src/protocol/binary.rs b/lib/rs/src/protocol/binary.rs
index 54613a5..e03ec94 100644
--- a/lib/rs/src/protocol/binary.rs
+++ b/lib/rs/src/protocol/binary.rs
@@ -16,14 +16,11 @@
 // under the License.
 
 use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
-use std::cell::RefCell;
 use std::convert::From;
-use std::io::{Read, Write};
-use std::rc::Rc;
 use try_from::TryFrom;
 
-use ::{ProtocolError, ProtocolErrorKind};
-use ::transport::TTransport;
+use {ProtocolError, ProtocolErrorKind};
+use transport::{TReadTransport, TWriteTransport};
 use super::{TFieldIdentifier, TInputProtocol, TInputProtocolFactory, TListIdentifier,
             TMapIdentifier, TMessageIdentifier, TMessageType};
 use super::{TOutputProtocol, TOutputProtocolFactory, TSetIdentifier, TStructIdentifier, TType};
@@ -41,32 +38,35 @@
 /// Create and use a `TBinaryInputProtocol`.
 ///
 /// ```no_run
-/// use std::cell::RefCell;
-/// use std::rc::Rc;
 /// use thrift::protocol::{TBinaryInputProtocol, TInputProtocol};
-/// use thrift::transport::{TTcpTransport, TTransport};
+/// use thrift::transport::TTcpChannel;
 ///
-/// let mut transport = TTcpTransport::new();
-/// transport.open("localhost:9090").unwrap();
-/// let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
+/// let mut channel = TTcpChannel::new();
+/// channel.open("localhost:9090").unwrap();
 ///
-/// let mut i_prot = TBinaryInputProtocol::new(transport, true);
+/// let mut protocol = TBinaryInputProtocol::new(channel, true);
 ///
-/// let recvd_bool = i_prot.read_bool().unwrap();
-/// let recvd_string = i_prot.read_string().unwrap();
+/// let recvd_bool = protocol.read_bool().unwrap();
+/// let recvd_string = protocol.read_string().unwrap();
 /// ```
-pub struct TBinaryInputProtocol<'a> {
+#[derive(Debug)]
+pub struct TBinaryInputProtocol<T>
+where
+    T: TReadTransport,
+{
     strict: bool,
-    transport: Rc<RefCell<Box<TTransport + 'a>>>,
+    transport: T,
 }
 
-impl<'a> TBinaryInputProtocol<'a> {
+impl<'a, T> TBinaryInputProtocol<T>
+where
+    T: TReadTransport,
+{
     /// Create a `TBinaryInputProtocol` that reads bytes from `transport`.
     ///
     /// Set `strict` to `true` if all incoming messages contain the protocol
     /// version number in the protocol header.
-    pub fn new(transport: Rc<RefCell<Box<TTransport + 'a>>>,
-               strict: bool) -> TBinaryInputProtocol<'a> {
+    pub fn new(transport: T, strict: bool) -> TBinaryInputProtocol<T> {
         TBinaryInputProtocol {
             strict: strict,
             transport: transport,
@@ -74,11 +74,14 @@
     }
 }
 
-impl<'a> TInputProtocol for TBinaryInputProtocol<'a> {
+impl<T> TInputProtocol for TBinaryInputProtocol<T>
+where
+    T: TReadTransport,
+{
     #[cfg_attr(feature = "cargo-clippy", allow(collapsible_if))]
     fn read_message_begin(&mut self) -> ::Result<TMessageIdentifier> {
         let mut first_bytes = vec![0; 4];
-        self.transport.borrow_mut().read_exact(&mut first_bytes[..])?;
+        self.transport.read_exact(&mut first_bytes[..])?;
 
         // the thrift version header is intentionally negative
         // so the first check we'll do is see if the sign bit is set
@@ -87,10 +90,14 @@
             // apparently we got a protocol-version header - check
             // it, and if it matches, read the rest of the fields
             if first_bytes[0..2] != [0x80, 0x01] {
-                Err(::Error::Protocol(ProtocolError {
-                    kind: ProtocolErrorKind::BadVersion,
-                    message: format!("received bad version: {:?}", &first_bytes[0..2]),
-                }))
+                Err(
+                    ::Error::Protocol(
+                        ProtocolError {
+                            kind: ProtocolErrorKind::BadVersion,
+                            message: format!("received bad version: {:?}", &first_bytes[0..2]),
+                        },
+                    ),
+                )
             } else {
                 let message_type: TMessageType = TryFrom::try_from(first_bytes[3])?;
                 let name = self.read_string()?;
@@ -103,17 +110,21 @@
             if self.strict {
                 // we're in strict mode however, and that always
                 // requires the protocol-version header to be written first
-                Err(::Error::Protocol(ProtocolError {
-                    kind: ProtocolErrorKind::BadVersion,
-                    message: format!("received bad version: {:?}", &first_bytes[0..2]),
-                }))
+                Err(
+                    ::Error::Protocol(
+                        ProtocolError {
+                            kind: ProtocolErrorKind::BadVersion,
+                            message: format!("received bad version: {:?}", &first_bytes[0..2]),
+                        },
+                    ),
+                )
             } else {
                 // in the non-strict version the first message field
                 // is the message name. strings (byte arrays) are length-prefixed,
                 // so we've just read the length in the first 4 bytes
                 let name_size = BigEndian::read_i32(&first_bytes) as usize;
                 let mut name_buf: Vec<u8> = Vec::with_capacity(name_size);
-                self.transport.borrow_mut().read_exact(&mut name_buf)?;
+                self.transport.read_exact(&mut name_buf)?;
                 let name = String::from_utf8(name_buf)?;
 
                 // read the rest of the fields
@@ -143,7 +154,7 @@
             TType::Stop => Ok(0),
             _ => self.read_i16(),
         }?;
-        Ok(TFieldIdentifier::new::<Option<String>, String, i16>(None, field_type, id))
+        Ok(TFieldIdentifier::new::<Option<String>, String, i16>(None, field_type, id),)
     }
 
     fn read_field_end(&mut self) -> ::Result<()> {
@@ -151,9 +162,12 @@
     }
 
     fn read_bytes(&mut self) -> ::Result<Vec<u8>> {
-        let num_bytes = self.transport.borrow_mut().read_i32::<BigEndian>()? as usize;
+        let num_bytes = self.transport.read_i32::<BigEndian>()? as usize;
         let mut buf = vec![0u8; num_bytes];
-        self.transport.borrow_mut().read_exact(&mut buf).map(|_| buf).map_err(From::from)
+        self.transport
+            .read_exact(&mut buf)
+            .map(|_| buf)
+            .map_err(From::from)
     }
 
     fn read_bool(&mut self) -> ::Result<bool> {
@@ -165,23 +179,31 @@
     }
 
     fn read_i8(&mut self) -> ::Result<i8> {
-        self.transport.borrow_mut().read_i8().map_err(From::from)
+        self.transport.read_i8().map_err(From::from)
     }
 
     fn read_i16(&mut self) -> ::Result<i16> {
-        self.transport.borrow_mut().read_i16::<BigEndian>().map_err(From::from)
+        self.transport
+            .read_i16::<BigEndian>()
+            .map_err(From::from)
     }
 
     fn read_i32(&mut self) -> ::Result<i32> {
-        self.transport.borrow_mut().read_i32::<BigEndian>().map_err(From::from)
+        self.transport
+            .read_i32::<BigEndian>()
+            .map_err(From::from)
     }
 
     fn read_i64(&mut self) -> ::Result<i64> {
-        self.transport.borrow_mut().read_i64::<BigEndian>().map_err(From::from)
+        self.transport
+            .read_i64::<BigEndian>()
+            .map_err(From::from)
     }
 
     fn read_double(&mut self) -> ::Result<f64> {
-        self.transport.borrow_mut().read_f64::<BigEndian>().map_err(From::from)
+        self.transport
+            .read_f64::<BigEndian>()
+            .map_err(From::from)
     }
 
     fn read_string(&mut self) -> ::Result<String> {
@@ -224,7 +246,7 @@
     //
 
     fn read_byte(&mut self) -> ::Result<u8> {
-        self.transport.borrow_mut().read_u8().map_err(From::from)
+        self.transport.read_u8().map_err(From::from)
     }
 }
 
@@ -240,8 +262,8 @@
 }
 
 impl TInputProtocolFactory for TBinaryInputProtocolFactory {
-    fn create<'a>(&mut self, transport: Rc<RefCell<Box<TTransport + 'a>>>) -> Box<TInputProtocol + 'a> {
-        Box::new(TBinaryInputProtocol::new(transport, true)) as Box<TInputProtocol + 'a>
+    fn create(&self, transport: Box<TReadTransport + Send>) -> Box<TInputProtocol + Send> {
+        Box::new(TBinaryInputProtocol::new(transport, true))
     }
 }
 
@@ -256,32 +278,35 @@
 /// Create and use a `TBinaryOutputProtocol`.
 ///
 /// ```no_run
-/// use std::cell::RefCell;
-/// use std::rc::Rc;
 /// use thrift::protocol::{TBinaryOutputProtocol, TOutputProtocol};
-/// use thrift::transport::{TTcpTransport, TTransport};
+/// use thrift::transport::TTcpChannel;
 ///
-/// let mut transport = TTcpTransport::new();
-/// transport.open("localhost:9090").unwrap();
-/// let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
+/// let mut channel = TTcpChannel::new();
+/// channel.open("localhost:9090").unwrap();
 ///
-/// let mut o_prot = TBinaryOutputProtocol::new(transport, true);
+/// let mut protocol = TBinaryOutputProtocol::new(channel, true);
 ///
-/// o_prot.write_bool(true).unwrap();
-/// o_prot.write_string("test_string").unwrap();
+/// protocol.write_bool(true).unwrap();
+/// protocol.write_string("test_string").unwrap();
 /// ```
-pub struct TBinaryOutputProtocol<'a> {
+#[derive(Debug)]
+pub struct TBinaryOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
     strict: bool,
-    transport: Rc<RefCell<Box<TTransport + 'a>>>,
+    pub transport: T, // FIXME: do not make public; only public for testing!
 }
 
-impl<'a> TBinaryOutputProtocol<'a> {
+impl<T> TBinaryOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
     /// Create a `TBinaryOutputProtocol` that writes bytes to `transport`.
     ///
     /// Set `strict` to `true` if all outgoing messages should contain the
     /// protocol version number in the protocol header.
-    pub fn new(transport: Rc<RefCell<Box<TTransport + 'a>>>,
-               strict: bool) -> TBinaryOutputProtocol<'a> {
+    pub fn new(transport: T, strict: bool) -> TBinaryOutputProtocol<T> {
         TBinaryOutputProtocol {
             strict: strict,
             transport: transport,
@@ -289,16 +314,22 @@
     }
 
     fn write_transport(&mut self, buf: &[u8]) -> ::Result<()> {
-        self.transport.borrow_mut().write(buf).map(|_| ()).map_err(From::from)
+        self.transport
+            .write(buf)
+            .map(|_| ())
+            .map_err(From::from)
     }
 }
 
-impl<'a> TOutputProtocol for TBinaryOutputProtocol<'a> {
+impl<T> TOutputProtocol for TBinaryOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
     fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> {
         if self.strict {
             let message_type: u8 = identifier.message_type.into();
             let header = BINARY_PROTOCOL_VERSION_1 | (message_type as u32);
-            self.transport.borrow_mut().write_u32::<BigEndian>(header)?;
+            self.transport.write_u32::<BigEndian>(header)?;
             self.write_string(&identifier.name)?;
             self.write_i32(identifier.sequence_number)
         } else {
@@ -322,11 +353,17 @@
 
     fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()> {
         if identifier.id.is_none() && identifier.field_type != TType::Stop {
-            return Err(::Error::Protocol(ProtocolError {
-                kind: ProtocolErrorKind::Unknown,
-                message: format!("cannot write identifier {:?} without sequence number",
-                                 &identifier),
-            }));
+            return Err(
+                ::Error::Protocol(
+                    ProtocolError {
+                        kind: ProtocolErrorKind::Unknown,
+                        message: format!(
+                            "cannot write identifier {:?} without sequence number",
+                            &identifier
+                        ),
+                    },
+                ),
+            );
         }
 
         self.write_byte(field_type_to_u8(identifier.field_type))?;
@@ -359,23 +396,31 @@
     }
 
     fn write_i8(&mut self, i: i8) -> ::Result<()> {
-        self.transport.borrow_mut().write_i8(i).map_err(From::from)
+        self.transport.write_i8(i).map_err(From::from)
     }
 
     fn write_i16(&mut self, i: i16) -> ::Result<()> {
-        self.transport.borrow_mut().write_i16::<BigEndian>(i).map_err(From::from)
+        self.transport
+            .write_i16::<BigEndian>(i)
+            .map_err(From::from)
     }
 
     fn write_i32(&mut self, i: i32) -> ::Result<()> {
-        self.transport.borrow_mut().write_i32::<BigEndian>(i).map_err(From::from)
+        self.transport
+            .write_i32::<BigEndian>(i)
+            .map_err(From::from)
     }
 
     fn write_i64(&mut self, i: i64) -> ::Result<()> {
-        self.transport.borrow_mut().write_i64::<BigEndian>(i).map_err(From::from)
+        self.transport
+            .write_i64::<BigEndian>(i)
+            .map_err(From::from)
     }
 
     fn write_double(&mut self, d: f64) -> ::Result<()> {
-        self.transport.borrow_mut().write_f64::<BigEndian>(d).map_err(From::from)
+        self.transport
+            .write_f64::<BigEndian>(d)
+            .map_err(From::from)
     }
 
     fn write_string(&mut self, s: &str) -> ::Result<()> {
@@ -401,10 +446,12 @@
     }
 
     fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()> {
-        let key_type = identifier.key_type
+        let key_type = identifier
+            .key_type
             .expect("map identifier to write should contain key type");
         self.write_byte(field_type_to_u8(key_type))?;
-        let val_type = identifier.value_type
+        let val_type = identifier
+            .value_type
             .expect("map identifier to write should contain value type");
         self.write_byte(field_type_to_u8(val_type))?;
         self.write_i32(identifier.size)
@@ -415,14 +462,14 @@
     }
 
     fn flush(&mut self) -> ::Result<()> {
-        self.transport.borrow_mut().flush().map_err(From::from)
+        self.transport.flush().map_err(From::from)
     }
 
     // utility
     //
 
     fn write_byte(&mut self, b: u8) -> ::Result<()> {
-        self.transport.borrow_mut().write_u8(b).map_err(From::from)
+        self.transport.write_u8(b).map_err(From::from)
     }
 }
 
@@ -438,8 +485,8 @@
 }
 
 impl TOutputProtocolFactory for TBinaryOutputProtocolFactory {
-    fn create(&mut self, transport: Rc<RefCell<Box<TTransport>>>) -> Box<TOutputProtocol> {
-        Box::new(TBinaryOutputProtocol::new(transport, true)) as Box<TOutputProtocol>
+    fn create(&self, transport: Box<TWriteTransport + Send>) -> Box<TOutputProtocol + Send> {
+        Box::new(TBinaryOutputProtocol::new(transport, true))
     }
 }
 
@@ -481,10 +528,14 @@
         0x10 => Ok(TType::Utf8),
         0x11 => Ok(TType::Utf16),
         unkn => {
-            Err(::Error::Protocol(ProtocolError {
-                kind: ProtocolErrorKind::InvalidData,
-                message: format!("cannot convert {} to TType", unkn),
-            }))
+            Err(
+                ::Error::Protocol(
+                    ProtocolError {
+                        kind: ProtocolErrorKind::InvalidData,
+                        message: format!("cannot convert {} to TType", unkn),
+                    },
+                ),
+            )
         }
     }
 }
@@ -492,56 +543,79 @@
 #[cfg(test)]
 mod tests {
 
-    use std::rc::Rc;
-    use std::cell::RefCell;
-
-    use ::protocol::{TFieldIdentifier, TMessageIdentifier, TMessageType, TInputProtocol,
-                     TListIdentifier, TMapIdentifier, TOutputProtocol, TSetIdentifier,
-                     TStructIdentifier, TType};
-    use ::transport::{TPassThruTransport, TTransport};
-    use ::transport::mem::TBufferTransport;
+    use protocol::{TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier,
+                   TMessageIdentifier, TMessageType, TOutputProtocol, TSetIdentifier,
+                   TStructIdentifier, TType};
+    use transport::{ReadHalf, TBufferChannel, TIoChannel, WriteHalf};
 
     use super::*;
 
     #[test]
     fn must_write_message_call_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         let ident = TMessageIdentifier::new("test", TMessageType::Call, 1);
         assert!(o_prot.write_message_begin(&ident).is_ok());
 
-        let buf = trans.borrow().write_buffer_to_vec();
+        let expected: [u8; 16] = [
+            0x80,
+            0x01,
+            0x00,
+            0x01,
+            0x00,
+            0x00,
+            0x00,
+            0x04,
+            0x74,
+            0x65,
+            0x73,
+            0x74,
+            0x00,
+            0x00,
+            0x00,
+            0x01,
+        ];
 
-        let expected: [u8; 16] = [0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x74, 0x65,
-                                  0x73, 0x74, 0x00, 0x00, 0x00, 0x01];
-
-        assert_eq!(&expected, buf.as_slice());
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
-
     #[test]
     fn must_write_message_reply_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         let ident = TMessageIdentifier::new("test", TMessageType::Reply, 10);
         assert!(o_prot.write_message_begin(&ident).is_ok());
 
-        let buf = trans.borrow().write_buffer_to_vec();
+        let expected: [u8; 16] = [
+            0x80,
+            0x01,
+            0x00,
+            0x02,
+            0x00,
+            0x00,
+            0x00,
+            0x04,
+            0x74,
+            0x65,
+            0x73,
+            0x74,
+            0x00,
+            0x00,
+            0x00,
+            0x0A,
+        ];
 
-        let expected: [u8; 16] = [0x80, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x74, 0x65,
-                                  0x73, 0x74, 0x00, 0x00, 0x00, 0x0A];
-
-        assert_eq!(&expected, buf.as_slice());
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_strict_message_begin() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         let sent_ident = TMessageIdentifier::new("test", TMessageType::Call, 1);
         assert!(o_prot.write_message_begin(&sent_ident).is_ok());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let received_ident = assert_success!(i_prot.read_message_begin());
         assert_eq!(&received_ident, &sent_ident);
@@ -564,24 +638,26 @@
 
     #[test]
     fn must_write_field_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
-        assert!(o_prot.write_field_begin(&TFieldIdentifier::new("some_field", TType::String, 22))
-            .is_ok());
+        assert!(
+            o_prot
+                .write_field_begin(&TFieldIdentifier::new("some_field", TType::String, 22))
+                .is_ok()
+        );
 
         let expected: [u8; 3] = [0x0B, 0x00, 0x16];
-        let buf = trans.borrow().write_buffer_to_vec();
-        assert_eq!(&expected, buf.as_slice());
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_field_begin() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         let sent_field_ident = TFieldIdentifier::new("foo", TType::I64, 20);
         assert!(o_prot.write_field_begin(&sent_field_ident).is_ok());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let expected_ident = TFieldIdentifier {
             name: None,
@@ -594,22 +670,21 @@
 
     #[test]
     fn must_write_stop_field() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         assert!(o_prot.write_field_stop().is_ok());
 
         let expected: [u8; 1] = [0x00];
-        let buf = trans.borrow().write_buffer_to_vec();
-        assert_eq!(&expected, buf.as_slice());
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_field_stop() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         assert!(o_prot.write_field_stop().is_ok());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let expected_ident = TFieldIdentifier {
             name: None,
@@ -628,23 +703,26 @@
 
     #[test]
     fn must_write_list_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
-        assert!(o_prot.write_list_begin(&TListIdentifier::new(TType::Bool, 5)).is_ok());
+        assert!(
+            o_prot
+                .write_list_begin(&TListIdentifier::new(TType::Bool, 5))
+                .is_ok()
+        );
 
         let expected: [u8; 5] = [0x02, 0x00, 0x00, 0x00, 0x05];
-        let buf = trans.borrow().write_buffer_to_vec();
-        assert_eq!(&expected, buf.as_slice());
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_list_begin() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         let ident = TListIdentifier::new(TType::List, 900);
         assert!(o_prot.write_list_begin(&ident).is_ok());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let received_ident = assert_success!(i_prot.read_list_begin());
         assert_eq!(&received_ident, &ident);
@@ -657,23 +735,26 @@
 
     #[test]
     fn must_write_set_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
-        assert!(o_prot.write_set_begin(&TSetIdentifier::new(TType::I16, 7)).is_ok());
+        assert!(
+            o_prot
+                .write_set_begin(&TSetIdentifier::new(TType::I16, 7))
+                .is_ok()
+        );
 
         let expected: [u8; 5] = [0x06, 0x00, 0x00, 0x00, 0x07];
-        let buf = trans.borrow().write_buffer_to_vec();
-        assert_eq!(&expected, buf.as_slice());
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_set_begin() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         let ident = TSetIdentifier::new(TType::I64, 2000);
         assert!(o_prot.write_set_begin(&ident).is_ok());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let received_ident_result = i_prot.read_set_begin();
         assert!(received_ident_result.is_ok());
@@ -687,24 +768,26 @@
 
     #[test]
     fn must_write_map_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
-        assert!(o_prot.write_map_begin(&TMapIdentifier::new(TType::I64, TType::Struct, 32))
-            .is_ok());
+        assert!(
+            o_prot
+                .write_map_begin(&TMapIdentifier::new(TType::I64, TType::Struct, 32))
+                .is_ok()
+        );
 
         let expected: [u8; 6] = [0x0A, 0x0C, 0x00, 0x00, 0x00, 0x20];
-        let buf = trans.borrow().write_buffer_to_vec();
-        assert_eq!(&expected, buf.as_slice());
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_map_begin() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         let ident = TMapIdentifier::new(TType::Map, TType::Set, 100);
         assert!(o_prot.write_map_begin(&ident).is_ok());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let received_ident = assert_success!(i_prot.read_map_begin());
         assert_eq!(&received_ident, &ident);
@@ -717,31 +800,29 @@
 
     #[test]
     fn must_write_bool_true() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         assert!(o_prot.write_bool(true).is_ok());
 
         let expected: [u8; 1] = [0x01];
-        let buf = trans.borrow().write_buffer_to_vec();
-        assert_eq!(&expected, buf.as_slice());
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_write_bool_false() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         assert!(o_prot.write_bool(false).is_ok());
 
         let expected: [u8; 1] = [0x00];
-        let buf = trans.borrow().write_buffer_to_vec();
-        assert_eq!(&expected, buf.as_slice());
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_read_bool_true() {
-        let (trans, mut i_prot, _) = test_objects();
+        let (mut i_prot, _) = test_objects();
 
-        trans.borrow_mut().set_readable_bytes(&[0x01]);
+        set_readable_bytes!(i_prot, &[0x01]);
 
         let read_bool = assert_success!(i_prot.read_bool());
         assert_eq!(read_bool, true);
@@ -749,9 +830,9 @@
 
     #[test]
     fn must_read_bool_false() {
-        let (trans, mut i_prot, _) = test_objects();
+        let (mut i_prot, _) = test_objects();
 
-        trans.borrow_mut().set_readable_bytes(&[0x00]);
+        set_readable_bytes!(i_prot, &[0x00]);
 
         let read_bool = assert_success!(i_prot.read_bool());
         assert_eq!(read_bool, false);
@@ -759,9 +840,9 @@
 
     #[test]
     fn must_allow_any_non_zero_value_to_be_interpreted_as_bool_true() {
-        let (trans, mut i_prot, _) = test_objects();
+        let (mut i_prot, _) = test_objects();
 
-        trans.borrow_mut().set_readable_bytes(&[0xAC]);
+        set_readable_bytes!(i_prot, &[0xAC]);
 
         let read_bool = assert_success!(i_prot.read_bool());
         assert_eq!(read_bool, true);
@@ -769,52 +850,77 @@
 
     #[test]
     fn must_write_bytes() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         let bytes: [u8; 10] = [0x0A, 0xCC, 0xD1, 0x84, 0x99, 0x12, 0xAB, 0xBB, 0x45, 0xDF];
 
         assert!(o_prot.write_bytes(&bytes).is_ok());
 
-        let buf = trans.borrow().write_buffer_to_vec();
+        let buf = o_prot.transport.write_bytes();
         assert_eq!(&buf[0..4], [0x00, 0x00, 0x00, 0x0A]); // length
         assert_eq!(&buf[4..], bytes); // actual bytes
     }
 
     #[test]
     fn must_round_trip_bytes() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
-        let bytes: [u8; 25] = [0x20, 0xFD, 0x18, 0x84, 0x99, 0x12, 0xAB, 0xBB, 0x45, 0xDF, 0x34,
-                               0xDC, 0x98, 0xA4, 0x6D, 0xF3, 0x99, 0xB4, 0xB7, 0xD4, 0x9C, 0xA5,
-                               0xB3, 0xC9, 0x88];
+        let bytes: [u8; 25] = [
+            0x20,
+            0xFD,
+            0x18,
+            0x84,
+            0x99,
+            0x12,
+            0xAB,
+            0xBB,
+            0x45,
+            0xDF,
+            0x34,
+            0xDC,
+            0x98,
+            0xA4,
+            0x6D,
+            0xF3,
+            0x99,
+            0xB4,
+            0xB7,
+            0xD4,
+            0x9C,
+            0xA5,
+            0xB3,
+            0xC9,
+            0x88,
+        ];
 
         assert!(o_prot.write_bytes(&bytes).is_ok());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let received_bytes = assert_success!(i_prot.read_bytes());
         assert_eq!(&received_bytes, &bytes);
     }
 
-    fn test_objects<'a>
-        ()
-        -> (Rc<RefCell<Box<TBufferTransport>>>, TBinaryInputProtocol<'a>, TBinaryOutputProtocol<'a>)
+    fn test_objects()
+        -> (TBinaryInputProtocol<ReadHalf<TBufferChannel>>,
+            TBinaryOutputProtocol<WriteHalf<TBufferChannel>>)
     {
+        let mem = TBufferChannel::with_capacity(40, 40);
 
-        let mem = Rc::new(RefCell::new(Box::new(TBufferTransport::with_capacity(40, 40))));
+        let (r_mem, w_mem) = mem.split().unwrap();
 
-        let inner: Box<TTransport> = Box::new(TPassThruTransport { inner: mem.clone() });
-        let inner = Rc::new(RefCell::new(inner));
+        let i_prot = TBinaryInputProtocol::new(r_mem, true);
+        let o_prot = TBinaryOutputProtocol::new(w_mem, true);
 
-        let i_prot = TBinaryInputProtocol::new(inner.clone(), true);
-        let o_prot = TBinaryOutputProtocol::new(inner.clone(), true);
-
-        (mem, i_prot, o_prot)
+        (i_prot, o_prot)
     }
 
-    fn assert_no_write<F: FnMut(&mut TBinaryOutputProtocol) -> ::Result<()>>(mut write_fn: F) {
-        let (trans, _, mut o_prot) = test_objects();
+    fn assert_no_write<F>(mut write_fn: F)
+    where
+        F: FnMut(&mut TBinaryOutputProtocol<WriteHalf<TBufferChannel>>) -> ::Result<()>,
+    {
+        let (_, mut o_prot) = test_objects();
         assert!(write_fn(&mut o_prot).is_ok());
-        assert_eq!(trans.borrow().write_buffer_as_ref().len(), 0);
+        assert_eq!(o_prot.transport.write_bytes().len(), 0);
     }
 }