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);
     }
 }
diff --git a/lib/rs/src/protocol/compact.rs b/lib/rs/src/protocol/compact.rs
index 353514d..dfe11f8 100644
--- a/lib/rs/src/protocol/compact.rs
+++ b/lib/rs/src/protocol/compact.rs
@@ -17,15 +17,12 @@
 
 use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
 use integer_encoding::{VarIntReader, VarIntWriter};
-use std::cell::RefCell;
 use std::convert::From;
-use std::rc::Rc;
-use std::io::{Read, Write};
 use try_from::TryFrom;
 
-use ::transport::TTransport;
-use super::{TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType,
-            TInputProtocol, TInputProtocolFactory};
+use transport::{TReadTransport, TWriteTransport};
+use super::{TFieldIdentifier, TInputProtocol, TInputProtocolFactory, TListIdentifier,
+            TMapIdentifier, TMessageIdentifier, TMessageType};
 use super::{TOutputProtocol, TOutputProtocolFactory, TSetIdentifier, TStructIdentifier, TType};
 
 const COMPACT_PROTOCOL_ID: u8 = 0x82;
@@ -39,21 +36,22 @@
 /// Create and use a `TCompactInputProtocol`.
 ///
 /// ```no_run
-/// use std::cell::RefCell;
-/// use std::rc::Rc;
 /// use thrift::protocol::{TCompactInputProtocol, 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 = TCompactInputProtocol::new(transport);
+/// let mut protocol = TCompactInputProtocol::new(channel);
 ///
-/// 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 TCompactInputProtocol<'a> {
+#[derive(Debug)]
+pub struct TCompactInputProtocol<T>
+where
+    T: TReadTransport,
+{
     // Identifier of the last field deserialized for a struct.
     last_read_field_id: i16,
     // Stack of the last read field ids (a new entry is added each time a nested struct is read).
@@ -63,12 +61,15 @@
     // and reading the field only occurs after the field id is read.
     pending_read_bool_value: Option<bool>,
     // Underlying transport used for byte-level operations.
-    transport: Rc<RefCell<Box<TTransport + 'a>>>,
+    transport: T,
 }
 
-impl<'a> TCompactInputProtocol<'a> {
+impl<T> TCompactInputProtocol<T>
+where
+    T: TReadTransport,
+{
     /// Create a `TCompactInputProtocol` that reads bytes from `transport`.
-    pub fn new(transport: Rc<RefCell<Box<TTransport + 'a>>>) -> TCompactInputProtocol<'a> {
+    pub fn new(transport: T) -> TCompactInputProtocol<T> {
         TCompactInputProtocol {
             last_read_field_id: 0,
             read_field_id_stack: Vec::new(),
@@ -87,21 +88,28 @@
             // high bits set high if count and type encoded separately
             element_count = possible_element_count as i32;
         } else {
-            element_count = self.transport.borrow_mut().read_varint::<u32>()? as i32;
+            element_count = self.transport.read_varint::<u32>()? as i32;
         }
 
         Ok((element_type, element_count))
     }
 }
 
-impl<'a> TInputProtocol for TCompactInputProtocol<'a> {
+impl<T> TInputProtocol for TCompactInputProtocol<T>
+where
+    T: TReadTransport,
+{
     fn read_message_begin(&mut self) -> ::Result<TMessageIdentifier> {
         let compact_id = self.read_byte()?;
         if compact_id != COMPACT_PROTOCOL_ID {
-            Err(::Error::Protocol(::ProtocolError {
-                kind: ::ProtocolErrorKind::BadVersion,
-                message: format!("invalid compact protocol header {:?}", compact_id),
-            }))
+            Err(
+                ::Error::Protocol(
+                    ::ProtocolError {
+                        kind: ::ProtocolErrorKind::BadVersion,
+                        message: format!("invalid compact protocol header {:?}", compact_id),
+                    },
+                ),
+            )
         } else {
             Ok(())
         }?;
@@ -109,11 +117,17 @@
         let type_and_byte = self.read_byte()?;
         let received_version = type_and_byte & COMPACT_VERSION_MASK;
         if received_version != COMPACT_VERSION {
-            Err(::Error::Protocol(::ProtocolError {
-                kind: ::ProtocolErrorKind::BadVersion,
-                message: format!("cannot process compact protocol version {:?}",
-                                 received_version),
-            }))
+            Err(
+                ::Error::Protocol(
+                    ::ProtocolError {
+                        kind: ::ProtocolErrorKind::BadVersion,
+                        message: format!(
+                            "cannot process compact protocol version {:?}",
+                            received_version
+                        ),
+                    },
+                ),
+            )
         } else {
             Ok(())
         }?;
@@ -125,7 +139,7 @@
 
         self.last_read_field_id = 0;
 
-        Ok(TMessageIdentifier::new(service_call_name, message_type, sequence_number))
+        Ok(TMessageIdentifier::new(service_call_name, message_type, sequence_number),)
     }
 
     fn read_message_end(&mut self) -> ::Result<()> {
@@ -165,9 +179,13 @@
 
         match field_type {
             TType::Stop => {
-                Ok(TFieldIdentifier::new::<Option<String>, String, Option<i16>>(None,
-                                                                                TType::Stop,
-                                                                                None))
+                Ok(
+                    TFieldIdentifier::new::<Option<String>, String, Option<i16>>(
+                        None,
+                        TType::Stop,
+                        None,
+                    ),
+                )
             }
             _ => {
                 if field_delta != 0 {
@@ -176,11 +194,13 @@
                     self.last_read_field_id = self.read_i16()?;
                 };
 
-                Ok(TFieldIdentifier {
-                    name: None,
-                    field_type: field_type,
-                    id: Some(self.last_read_field_id),
-                })
+                Ok(
+                    TFieldIdentifier {
+                        name: None,
+                        field_type: field_type,
+                        id: Some(self.last_read_field_id),
+                    },
+                )
             }
         }
     }
@@ -198,10 +218,14 @@
                     0x01 => Ok(true),
                     0x02 => Ok(false),
                     unkn => {
-                        Err(::Error::Protocol(::ProtocolError {
-                            kind: ::ProtocolErrorKind::InvalidData,
-                            message: format!("cannot convert {} into bool", unkn),
-                        }))
+                        Err(
+                            ::Error::Protocol(
+                                ::ProtocolError {
+                                    kind: ::ProtocolErrorKind::InvalidData,
+                                    message: format!("cannot convert {} into bool", unkn),
+                                },
+                            ),
+                        )
                     }
                 }
             }
@@ -209,9 +233,12 @@
     }
 
     fn read_bytes(&mut self) -> ::Result<Vec<u8>> {
-        let len = self.transport.borrow_mut().read_varint::<u32>()?;
+        let len = self.transport.read_varint::<u32>()?;
         let mut buf = vec![0u8; len as usize];
-        self.transport.borrow_mut().read_exact(&mut buf).map_err(From::from).map(|_| buf)
+        self.transport
+            .read_exact(&mut buf)
+            .map_err(From::from)
+            .map(|_| buf)
     }
 
     fn read_i8(&mut self) -> ::Result<i8> {
@@ -219,19 +246,21 @@
     }
 
     fn read_i16(&mut self) -> ::Result<i16> {
-        self.transport.borrow_mut().read_varint::<i16>().map_err(From::from)
+        self.transport.read_varint::<i16>().map_err(From::from)
     }
 
     fn read_i32(&mut self) -> ::Result<i32> {
-        self.transport.borrow_mut().read_varint::<i32>().map_err(From::from)
+        self.transport.read_varint::<i32>().map_err(From::from)
     }
 
     fn read_i64(&mut self) -> ::Result<i64> {
-        self.transport.borrow_mut().read_varint::<i64>().map_err(From::from)
+        self.transport.read_varint::<i64>().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> {
@@ -258,7 +287,7 @@
     }
 
     fn read_map_begin(&mut self) -> ::Result<TMapIdentifier> {
-        let element_count = self.transport.borrow_mut().read_varint::<u32>()? as i32;
+        let element_count = self.transport.read_varint::<u32>()? as i32;
         if element_count == 0 {
             Ok(TMapIdentifier::new(None, None, 0))
         } else {
@@ -278,7 +307,10 @@
 
     fn read_byte(&mut self) -> ::Result<u8> {
         let mut buf = [0u8; 1];
-        self.transport.borrow_mut().read_exact(&mut buf).map_err(From::from).map(|_| buf[0])
+        self.transport
+            .read_exact(&mut buf)
+            .map_err(From::from)
+            .map(|_| buf[0])
     }
 }
 
@@ -294,8 +326,8 @@
 }
 
 impl TInputProtocolFactory for TCompactInputProtocolFactory {
-    fn create<'a>(&mut self, transport: Rc<RefCell<Box<TTransport + 'a>>>) -> Box<TInputProtocol + 'a> {
-        Box::new(TCompactInputProtocol::new(transport)) as Box<TInputProtocol + 'a>
+    fn create(&self, transport: Box<TReadTransport + Send>) -> Box<TInputProtocol + Send> {
+        Box::new(TCompactInputProtocol::new(transport))
     }
 }
 
@@ -306,35 +338,39 @@
 /// Create and use a `TCompactOutputProtocol`.
 ///
 /// ```no_run
-/// use std::cell::RefCell;
-/// use std::rc::Rc;
 /// use thrift::protocol::{TCompactOutputProtocol, 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 = TCompactOutputProtocol::new(transport);
+/// let mut protocol = TCompactOutputProtocol::new(channel);
 ///
-/// 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 TCompactOutputProtocol<'a> {
+#[derive(Debug)]
+pub struct TCompactOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
     // Identifier of the last field serialized for a struct.
     last_write_field_id: i16,
-    // Stack of the last written field ids (a new entry is added each time a nested struct is written).
+    // Stack of the last written field ids (new entry added each time a nested struct is written).
     write_field_id_stack: Vec<i16>,
     // Field identifier of the boolean field to be written.
     // Saved because boolean fields and their value are encoded in a single byte
     pending_write_bool_field_identifier: Option<TFieldIdentifier>,
     // Underlying transport used for byte-level operations.
-    transport: Rc<RefCell<Box<TTransport + 'a>>>,
+    transport: T,
 }
 
-impl<'a> TCompactOutputProtocol<'a> {
+impl<T> TCompactOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
     /// Create a `TCompactOutputProtocol` that writes bytes to `transport`.
-    pub fn new(transport: Rc<RefCell<Box<TTransport + 'a>>>) -> TCompactOutputProtocol<'a> {
+    pub fn new(transport: T) -> TCompactOutputProtocol<T> {
         TCompactOutputProtocol {
             last_write_field_id: 0,
             write_field_id_stack: Vec::new(),
@@ -365,7 +401,6 @@
             let header = 0xF0 | elem_identifier;
             self.write_byte(header)?;
             self.transport
-                .borrow_mut()
                 .write_varint(element_count as u32)
                 .map_err(From::from)
                 .map(|_| ())
@@ -379,7 +414,10 @@
     }
 }
 
-impl<'a> TOutputProtocol for TCompactOutputProtocol<'a> {
+impl<T> TOutputProtocol for TCompactOutputProtocol<T>
+where
+    T: TWriteTransport,
+{
     fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> {
         self.write_byte(COMPACT_PROTOCOL_ID)?;
         self.write_byte((u8::from(identifier.message_type) << 5) | COMPACT_VERSION)?;
@@ -401,8 +439,9 @@
 
     fn write_struct_end(&mut self) -> ::Result<()> {
         self.assert_no_pending_bool_write();
-        self.last_write_field_id =
-            self.write_field_id_stack.pop().expect("should have previous field ids");
+        self.last_write_field_id = self.write_field_id_stack
+            .pop()
+            .expect("should have previous field ids");
         Ok(())
     }
 
@@ -410,16 +449,20 @@
         match identifier.field_type {
             TType::Bool => {
                 if self.pending_write_bool_field_identifier.is_some() {
-                    panic!("should not have a pending bool while writing another bool with id: \
+                    panic!(
+                        "should not have a pending bool while writing another bool with id: \
                             {:?}",
-                           identifier)
+                        identifier
+                    )
                 }
                 self.pending_write_bool_field_identifier = Some(identifier.clone());
                 Ok(())
             }
             _ => {
                 let field_type = type_to_u8(identifier.field_type);
-                let field_id = identifier.id.expect("non-stop field should have field id");
+                let field_id = identifier
+                    .id
+                    .expect("non-stop field should have field id");
                 self.write_field_header(field_type, field_id)
             }
         }
@@ -453,8 +496,8 @@
     }
 
     fn write_bytes(&mut self, b: &[u8]) -> ::Result<()> {
-        self.transport.borrow_mut().write_varint(b.len() as u32)?;
-        self.transport.borrow_mut().write_all(b).map_err(From::from)
+        self.transport.write_varint(b.len() as u32)?;
+        self.transport.write_all(b).map_err(From::from)
     }
 
     fn write_i8(&mut self, i: i8) -> ::Result<()> {
@@ -462,19 +505,30 @@
     }
 
     fn write_i16(&mut self, i: i16) -> ::Result<()> {
-        self.transport.borrow_mut().write_varint(i).map_err(From::from).map(|_| ())
+        self.transport
+            .write_varint(i)
+            .map_err(From::from)
+            .map(|_| ())
     }
 
     fn write_i32(&mut self, i: i32) -> ::Result<()> {
-        self.transport.borrow_mut().write_varint(i).map_err(From::from).map(|_| ())
+        self.transport
+            .write_varint(i)
+            .map_err(From::from)
+            .map(|_| ())
     }
 
     fn write_i64(&mut self, i: i64) -> ::Result<()> {
-        self.transport.borrow_mut().write_varint(i).map_err(From::from).map(|_| ())
+        self.transport
+            .write_varint(i)
+            .map_err(From::from)
+            .map(|_| ())
     }
 
     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<()> {
@@ -501,13 +555,15 @@
         if identifier.size == 0 {
             self.write_byte(0)
         } else {
-            self.transport.borrow_mut().write_varint(identifier.size as u32)?;
+            self.transport.write_varint(identifier.size as u32)?;
 
-            let key_type = identifier.key_type
+            let key_type = identifier
+                .key_type
                 .expect("map identifier to write should contain key type");
             let key_type_byte = collection_type_to_u8(key_type) << 4;
 
-            let val_type = identifier.value_type
+            let val_type = identifier
+                .value_type
                 .expect("map identifier to write should contain value type");
             let val_type_byte = collection_type_to_u8(val_type);
 
@@ -521,14 +577,17 @@
     }
 
     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(&[b]).map_err(From::from).map(|_| ())
+        self.transport
+            .write(&[b])
+            .map_err(From::from)
+            .map(|_| ())
     }
 }
 
@@ -544,8 +603,8 @@
 }
 
 impl TOutputProtocolFactory for TCompactOutputProtocolFactory {
-    fn create(&mut self, transport: Rc<RefCell<Box<TTransport>>>) -> Box<TOutputProtocol> {
-        Box::new(TCompactOutputProtocol::new(transport)) as Box<TOutputProtocol>
+    fn create(&self, transport: Box<TWriteTransport + Send>) -> Box<TOutputProtocol + Send> {
+        Box::new(TCompactOutputProtocol::new(transport))
     }
 }
 
@@ -594,10 +653,14 @@
         0x0B => Ok(TType::Map),
         0x0C => Ok(TType::Struct),
         unkn => {
-            Err(::Error::Protocol(::ProtocolError {
-                kind: ::ProtocolErrorKind::InvalidData,
-                message: format!("cannot convert {} into TType", unkn),
-            }))
+            Err(
+                ::Error::Protocol(
+                    ::ProtocolError {
+                        kind: ::ProtocolErrorKind::InvalidData,
+                        message: format!("cannot convert {} into TType", unkn),
+                    },
+                ),
+            )
         }
     }
 }
@@ -605,54 +668,65 @@
 #[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_begin_0() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new("foo", TMessageType::Call, 431)));
 
-        let expected: [u8; 8] =
-            [0x82 /* protocol ID */, 0x21 /* message type | protocol version */, 0xDE,
-             0x06 /* zig-zag varint sequence number */, 0x03 /* message-name length */,
-             0x66, 0x6F, 0x6F /* "foo" */];
+        let expected: [u8; 8] = [
+            0x82, /* protocol ID */
+            0x21, /* message type | protocol version */
+            0xDE,
+            0x06, /* zig-zag varint sequence number */
+            0x03, /* message-name length */
+            0x66,
+            0x6F,
+            0x6F /* "foo" */,
+        ];
 
-        assert_eq!(trans.borrow().write_buffer_as_ref(), &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_write_message_begin_1() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
-        assert_success!(o_prot.write_message_begin(&TMessageIdentifier::new("bar", TMessageType::Reply, 991828)));
+        assert_success!(
+            o_prot.write_message_begin(&TMessageIdentifier::new("bar", TMessageType::Reply, 991828))
+        );
 
-        let expected: [u8; 9] =
-            [0x82 /* protocol ID */, 0x41 /* message type | protocol version */, 0xA8,
-             0x89, 0x79 /* zig-zag varint sequence number */,
-             0x03 /* message-name length */, 0x62, 0x61, 0x72 /* "bar" */];
+        let expected: [u8; 9] = [
+            0x82, /* protocol ID */
+            0x41, /* message type | protocol version */
+            0xA8,
+            0x89,
+            0x79, /* zig-zag varint sequence number */
+            0x03, /* message-name length */
+            0x62,
+            0x61,
+            0x72 /* "bar" */,
+        ];
 
-        assert_eq!(trans.borrow().write_buffer_as_ref(), &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_message_begin() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         let ident = TMessageIdentifier::new("service_call", TMessageType::Call, 1283948);
 
         assert_success!(o_prot.write_message_begin(&ident));
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let res = assert_success!(i_prot.read_message_begin());
         assert_eq!(&res, &ident);
@@ -668,7 +742,7 @@
 
     #[test]
     fn must_write_struct_with_delta_fields() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         // no bytes should be written however
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -692,20 +766,20 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        // get bytes written
-        let buf = trans.borrow_mut().write_buffer_to_vec();
+        let expected: [u8; 5] = [
+            0x03, /* field type */
+            0x00, /* first field id */
+            0x44, /* field delta (4) | field type */
+            0x59, /* field delta (5) | field type */
+            0x00 /* field stop */,
+        ];
 
-        let expected: [u8; 5] = [0x03 /* field type */, 0x00 /* first field id */,
-                                 0x44 /* field delta (4) | field type */,
-                                 0x59 /* field delta (5) | field type */,
-                                 0x00 /* field stop */];
-
-        assert_eq!(&buf, &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_struct_with_delta_fields() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         // no bytes should be written however
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -732,40 +806,57 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         // read the struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_1 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_1,
-                   TFieldIdentifier { name: None, ..field_ident_1 });
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_2 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_2,
-                   TFieldIdentifier { name: None, ..field_ident_2 });
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_3 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_3,
-                   TFieldIdentifier { name: None, ..field_ident_3 });
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_4 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_4,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
 
         assert_success!(i_prot.read_struct_end());
     }
 
     #[test]
     fn must_write_struct_with_non_zero_initial_field_and_delta_fields() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         // no bytes should be written however
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -789,20 +880,19 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        // get bytes written
-        let buf = trans.borrow_mut().write_buffer_to_vec();
+        let expected: [u8; 4] = [
+            0x15, /* field delta (1) | field type */
+            0x1A, /* field delta (1) | field type */
+            0x48, /* field delta (4) | field type */
+            0x00 /* field stop */,
+        ];
 
-        let expected: [u8; 4] = [0x15 /* field delta (1) | field type */,
-                                 0x1A /* field delta (1) | field type */,
-                                 0x48 /* field delta (4) | field type */,
-                                 0x00 /* field stop */];
-
-        assert_eq!(&buf, &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_struct_with_non_zero_initial_field_and_delta_fields() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         // no bytes should be written however
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -829,40 +919,57 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         // read the struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_1 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_1,
-                   TFieldIdentifier { name: None, ..field_ident_1 });
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_2 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_2,
-                   TFieldIdentifier { name: None, ..field_ident_2 });
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_3 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_3,
-                   TFieldIdentifier { name: None, ..field_ident_3 });
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_4 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_4,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
 
         assert_success!(i_prot.read_struct_end());
     }
 
     #[test]
     fn must_write_struct_with_long_fields() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         // no bytes should be written however
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -885,21 +992,23 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        // get bytes written
-        let buf = trans.borrow_mut().write_buffer_to_vec();
+        let expected: [u8; 8] = [
+            0x05, /* field type */
+            0x00, /* first field id */
+            0x06, /* field type */
+            0x20, /* zig-zag varint field id */
+            0x0A, /* field type */
+            0xC6,
+            0x01, /* zig-zag varint field id */
+            0x00 /* field stop */,
+        ];
 
-        let expected: [u8; 8] =
-            [0x05 /* field type */, 0x00 /* first field id */,
-             0x06 /* field type */, 0x20 /* zig-zag varint field id */,
-             0x0A /* field type */, 0xC6, 0x01 /* zig-zag varint field id */,
-             0x00 /* field stop */];
-
-        assert_eq!(&buf, &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_struct_with_long_fields() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         // no bytes should be written however
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -925,40 +1034,57 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         // read the struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_1 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_1,
-                   TFieldIdentifier { name: None, ..field_ident_1 });
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_2 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_2,
-                   TFieldIdentifier { name: None, ..field_ident_2 });
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_3 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_3,
-                   TFieldIdentifier { name: None, ..field_ident_3 });
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_4 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_4,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
 
         assert_success!(i_prot.read_struct_end());
     }
 
     #[test]
     fn must_write_struct_with_mix_of_long_and_delta_fields() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         // no bytes should be written however
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -989,22 +1115,25 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        // get bytes written
-        let buf = trans.borrow_mut().write_buffer_to_vec();
+        let expected: [u8; 10] = [
+            0x16, /* field delta (1) | field type */
+            0x85, /* field delta (8) | field type */
+            0x0A, /* field type */
+            0xD0,
+            0x0F, /* zig-zag varint field id */
+            0x0A, /* field type */
+            0xA2,
+            0x1F, /* zig-zag varint field id */
+            0x3A, /* field delta (3) | field type */
+            0x00 /* field stop */,
+        ];
 
-        let expected: [u8; 10] =
-            [0x16 /* field delta (1) | field type */,
-             0x85 /* field delta (8) | field type */, 0x0A /* field type */, 0xD0,
-             0x0F /* zig-zag varint field id */, 0x0A /* field type */, 0xA2,
-             0x1F /* zig-zag varint field id */,
-             0x3A /* field delta (3) | field type */, 0x00 /* field stop */];
-
-        assert_eq!(&buf, &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_struct_with_mix_of_long_and_delta_fields() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         // no bytes should be written however
         let struct_ident = TStructIdentifier::new("foo");
@@ -1041,43 +1170,70 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         // read the struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_1 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_1,
-                   TFieldIdentifier { name: None, ..field_ident_1 });
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_2 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_2,
-                   TFieldIdentifier { name: None, ..field_ident_2 });
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_3 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_3,
-                   TFieldIdentifier { name: None, ..field_ident_3 });
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_4 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_4,
-                   TFieldIdentifier { name: None, ..field_ident_4 });
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_5 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_5,
-                   TFieldIdentifier { name: None, ..field_ident_5 });
+        assert_eq!(
+            read_ident_5,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_5
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_6 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_6,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_6,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
 
         assert_success!(i_prot.read_struct_end());
     }
@@ -1087,7 +1243,7 @@
         // last field of the containing struct is a delta
         // first field of the the contained struct is a delta
 
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         // start containing struct
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -1123,17 +1279,17 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        // get bytes written
-        let buf = trans.borrow_mut().write_buffer_to_vec();
+        let expected: [u8; 7] = [
+            0x16, /* field delta (1) | field type */
+            0x85, /* field delta (8) | field type */
+            0x73, /* field delta (7) | field type */
+            0x07, /* field type */
+            0x30, /* zig-zag varint field id */
+            0x00, /* field stop - contained */
+            0x00 /* field stop - containing */,
+        ];
 
-        let expected: [u8; 7] =
-            [0x16 /* field delta (1) | field type */,
-             0x85 /* field delta (8) | field type */,
-             0x73 /* field delta (7) | field type */, 0x07 /* field type */,
-             0x30 /* zig-zag varint field id */, 0x00 /* field stop - contained */,
-             0x00 /* field stop - containing */];
-
-        assert_eq!(&buf, &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
@@ -1141,7 +1297,7 @@
         // last field of the containing struct is a delta
         // first field of the the contained struct is a delta
 
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         // start containing struct
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -1181,52 +1337,76 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         // read containing struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_1 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_1,
-                   TFieldIdentifier { name: None, ..field_ident_1 });
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_2 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_2,
-                   TFieldIdentifier { name: None, ..field_ident_2 });
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         // read contained struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_3 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_3,
-                   TFieldIdentifier { name: None, ..field_ident_3 });
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_4 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_4,
-                   TFieldIdentifier { name: None, ..field_ident_4 });
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         // end contained struct
         let read_ident_6 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_6,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_6,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
         assert_success!(i_prot.read_struct_end());
 
         // end containing struct
         let read_ident_7 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_7,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_7,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
         assert_success!(i_prot.read_struct_end());
     }
 
@@ -1235,7 +1415,7 @@
         // last field of the containing struct is a delta
         // first field of the the contained struct is a full write
 
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         // start containing struct
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -1271,17 +1451,17 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        // get bytes written
-        let buf = trans.borrow_mut().write_buffer_to_vec();
+        let expected: [u8; 7] = [
+            0x16, /* field delta (1) | field type */
+            0x85, /* field delta (8) | field type */
+            0x07, /* field type */
+            0x30, /* zig-zag varint field id */
+            0x33, /* field delta (3) | field type */
+            0x00, /* field stop - contained */
+            0x00 /* field stop - containing */,
+        ];
 
-        let expected: [u8; 7] =
-            [0x16 /* field delta (1) | field type */,
-             0x85 /* field delta (8) | field type */, 0x07 /* field type */,
-             0x30 /* zig-zag varint field id */,
-             0x33 /* field delta (3) | field type */, 0x00 /* field stop - contained */,
-             0x00 /* field stop - containing */];
-
-        assert_eq!(&buf, &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
@@ -1289,7 +1469,7 @@
         // last field of the containing struct is a delta
         // first field of the the contained struct is a full write
 
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         // start containing struct
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -1329,52 +1509,76 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         // read containing struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_1 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_1,
-                   TFieldIdentifier { name: None, ..field_ident_1 });
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_2 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_2,
-                   TFieldIdentifier { name: None, ..field_ident_2 });
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         // read contained struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_3 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_3,
-                   TFieldIdentifier { name: None, ..field_ident_3 });
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_4 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_4,
-                   TFieldIdentifier { name: None, ..field_ident_4 });
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         // end contained struct
         let read_ident_6 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_6,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_6,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
         assert_success!(i_prot.read_struct_end());
 
         // end containing struct
         let read_ident_7 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_7,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_7,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
         assert_success!(i_prot.read_struct_end());
     }
 
@@ -1383,7 +1587,7 @@
         // last field of the containing struct is a full write
         // first field of the the contained struct is a delta write
 
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         // start containing struct
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -1419,21 +1623,22 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        // get bytes written
-        let buf = trans.borrow_mut().write_buffer_to_vec();
+        let expected: [u8; 7] = [
+            0x16, /* field delta (1) | field type */
+            0x08, /* field type */
+            0x2A, /* zig-zag varint field id */
+            0x77, /* field delta(7) | field type */
+            0x33, /* field delta (3) | field type */
+            0x00, /* field stop - contained */
+            0x00 /* field stop - containing */,
+        ];
 
-        let expected: [u8; 7] =
-            [0x16 /* field delta (1) | field type */, 0x08 /* field type */,
-             0x2A /* zig-zag varint field id */, 0x77 /* field delta(7) | field type */,
-             0x33 /* field delta (3) | field type */, 0x00 /* field stop - contained */,
-             0x00 /* field stop - containing */];
-
-        assert_eq!(&buf, &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_nested_structs_2() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         // start containing struct
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -1473,52 +1678,76 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         // read containing struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_1 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_1,
-                   TFieldIdentifier { name: None, ..field_ident_1 });
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_2 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_2,
-                   TFieldIdentifier { name: None, ..field_ident_2 });
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         // read contained struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_3 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_3,
-                   TFieldIdentifier { name: None, ..field_ident_3 });
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_4 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_4,
-                   TFieldIdentifier { name: None, ..field_ident_4 });
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         // end contained struct
         let read_ident_6 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_6,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_6,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
         assert_success!(i_prot.read_struct_end());
 
         // end containing struct
         let read_ident_7 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_7,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_7,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
         assert_success!(i_prot.read_struct_end());
     }
 
@@ -1527,7 +1756,7 @@
         // last field of the containing struct is a full write
         // first field of the the contained struct is a full write
 
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         // start containing struct
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -1563,17 +1792,18 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        // get bytes written
-        let buf = trans.borrow_mut().write_buffer_to_vec();
+        let expected: [u8; 8] = [
+            0x16, /* field delta (1) | field type */
+            0x08, /* field type */
+            0x2A, /* zig-zag varint field id */
+            0x07, /* field type */
+            0x2A, /* zig-zag varint field id */
+            0x63, /* field delta (6) | field type */
+            0x00, /* field stop - contained */
+            0x00 /* field stop - containing */,
+        ];
 
-        let expected: [u8; 8] =
-            [0x16 /* field delta (1) | field type */, 0x08 /* field type */,
-             0x2A /* zig-zag varint field id */, 0x07 /* field type */,
-             0x2A /* zig-zag varint field id */,
-             0x63 /* field delta (6) | field type */, 0x00 /* field stop - contained */,
-             0x00 /* field stop - containing */];
-
-        assert_eq!(&buf, &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
@@ -1581,7 +1811,7 @@
         // last field of the containing struct is a full write
         // first field of the the contained struct is a full write
 
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         // start containing struct
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -1621,58 +1851,82 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         // read containing struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_1 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_1,
-                   TFieldIdentifier { name: None, ..field_ident_1 });
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_2 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_2,
-                   TFieldIdentifier { name: None, ..field_ident_2 });
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         // read contained struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_3 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_3,
-                   TFieldIdentifier { name: None, ..field_ident_3 });
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         let read_ident_4 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_4,
-                   TFieldIdentifier { name: None, ..field_ident_4 });
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
         assert_success!(i_prot.read_field_end());
 
         // end contained struct
         let read_ident_6 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_6,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_6,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
         assert_success!(i_prot.read_struct_end());
 
         // end containing struct
         let read_ident_7 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_7,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_7,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
         assert_success!(i_prot.read_struct_end());
     }
 
     #[test]
     fn must_write_bool_field() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         // no bytes should be written however
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
@@ -1703,20 +1957,22 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        // get bytes written
-        let buf = trans.borrow_mut().write_buffer_to_vec();
+        let expected: [u8; 7] = [
+            0x11, /* field delta (1) | true */
+            0x82, /* field delta (8) | false */
+            0x01, /* true */
+            0x34, /* field id */
+            0x02, /* false */
+            0x5A, /* field id */
+            0x00 /* stop field */,
+        ];
 
-        let expected: [u8; 7] = [0x11 /* field delta (1) | true */,
-                                 0x82 /* field delta (8) | false */, 0x01 /* true */,
-                                 0x34 /* field id */, 0x02 /* false */,
-                                 0x5A /* field id */, 0x00 /* stop field */];
-
-        assert_eq!(&buf, &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_bool_field() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         // no bytes should be written however
         let struct_ident = TStructIdentifier::new("foo");
@@ -1752,46 +2008,68 @@
         assert_success!(o_prot.write_field_stop());
         assert_success!(o_prot.write_struct_end());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         // read the struct back
         assert_success!(i_prot.read_struct_begin());
 
         let read_ident_1 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_1,
-                   TFieldIdentifier { name: None, ..field_ident_1 });
+        assert_eq!(
+            read_ident_1,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_1
+            }
+        );
         let read_value_1 = assert_success!(i_prot.read_bool());
         assert_eq!(read_value_1, true);
         assert_success!(i_prot.read_field_end());
 
         let read_ident_2 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_2,
-                   TFieldIdentifier { name: None, ..field_ident_2 });
+        assert_eq!(
+            read_ident_2,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_2
+            }
+        );
         let read_value_2 = assert_success!(i_prot.read_bool());
         assert_eq!(read_value_2, false);
         assert_success!(i_prot.read_field_end());
 
         let read_ident_3 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_3,
-                   TFieldIdentifier { name: None, ..field_ident_3 });
+        assert_eq!(
+            read_ident_3,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_3
+            }
+        );
         let read_value_3 = assert_success!(i_prot.read_bool());
         assert_eq!(read_value_3, true);
         assert_success!(i_prot.read_field_end());
 
         let read_ident_4 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_4,
-                   TFieldIdentifier { name: None, ..field_ident_4 });
+        assert_eq!(
+            read_ident_4,
+            TFieldIdentifier {
+                name: None,
+                ..field_ident_4
+            }
+        );
         let read_value_4 = assert_success!(i_prot.read_bool());
         assert_eq!(read_value_4, false);
         assert_success!(i_prot.read_field_end());
 
         let read_ident_5 = assert_success!(i_prot.read_field_begin());
-        assert_eq!(read_ident_5,
-                   TFieldIdentifier {
-                       name: None,
-                       field_type: TType::Stop,
-                       id: None,
-                   });
+        assert_eq!(
+            read_ident_5,
+            TFieldIdentifier {
+                name: None,
+                field_type: TType::Stop,
+                id: None,
+            }
+        );
 
         assert_success!(i_prot.read_struct_end());
     }
@@ -1799,7 +2077,7 @@
     #[test]
     #[should_panic]
     fn must_fail_if_write_field_end_without_writing_bool_value() {
-        let (_, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
         assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
         o_prot.write_field_end().unwrap();
@@ -1808,7 +2086,7 @@
     #[test]
     #[should_panic]
     fn must_fail_if_write_stop_field_without_writing_bool_value() {
-        let (_, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
         assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
         o_prot.write_field_stop().unwrap();
@@ -1817,7 +2095,7 @@
     #[test]
     #[should_panic]
     fn must_fail_if_write_struct_end_without_writing_bool_value() {
-        let (_, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
         assert_success!(o_prot.write_struct_begin(&TStructIdentifier::new("foo")));
         assert_success!(o_prot.write_field_begin(&TFieldIdentifier::new("foo", TType::Bool, 1)));
         o_prot.write_struct_end().unwrap();
@@ -1826,7 +2104,7 @@
     #[test]
     #[should_panic]
     fn must_fail_if_write_struct_end_without_any_fields() {
-        let (_, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
         o_prot.write_struct_end().unwrap();
     }
 
@@ -1837,24 +2115,24 @@
 
     #[test]
     fn must_write_small_sized_list_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         assert_success!(o_prot.write_list_begin(&TListIdentifier::new(TType::I64, 4)));
 
         let expected: [u8; 1] = [0x46 /* size | elem_type */];
 
-        assert_eq!(trans.borrow().write_buffer_as_ref(), &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_small_sized_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::I08, 10);
 
         assert_success!(o_prot.write_list_begin(&ident));
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let res = assert_success!(i_prot.read_list_begin());
         assert_eq!(&res, &ident);
@@ -1862,26 +2140,29 @@
 
     #[test]
     fn must_write_large_sized_list_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         let res = o_prot.write_list_begin(&TListIdentifier::new(TType::List, 9999));
         assert!(res.is_ok());
 
-        let expected: [u8; 3] = [0xF9 /* 0xF0 | elem_type */, 0x8F,
-                                 0x4E /* size as varint */];
+        let expected: [u8; 3] = [
+            0xF9, /* 0xF0 | elem_type */
+            0x8F,
+            0x4E /* size as varint */,
+        ];
 
-        assert_eq!(trans.borrow().write_buffer_as_ref(), &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_large_sized_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::Set, 47381);
 
         assert_success!(o_prot.write_list_begin(&ident));
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let res = assert_success!(i_prot.read_list_begin());
         assert_eq!(&res, &ident);
@@ -1894,24 +2175,24 @@
 
     #[test]
     fn must_write_small_sized_set_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Struct, 2)));
 
         let expected: [u8; 1] = [0x2C /* size | elem_type */];
 
-        assert_eq!(trans.borrow().write_buffer_as_ref(), &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_small_sized_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::I16, 7);
 
         assert_success!(o_prot.write_set_begin(&ident));
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let res = assert_success!(i_prot.read_set_begin());
         assert_eq!(&res, &ident);
@@ -1919,25 +2200,29 @@
 
     #[test]
     fn must_write_large_sized_set_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         assert_success!(o_prot.write_set_begin(&TSetIdentifier::new(TType::Double, 23891)));
 
-        let expected: [u8; 4] = [0xF7 /* 0xF0 | elem_type */, 0xD3, 0xBA,
-                                 0x01 /* size as varint */];
+        let expected: [u8; 4] = [
+            0xF7, /* 0xF0 | elem_type */
+            0xD3,
+            0xBA,
+            0x01 /* size as varint */,
+        ];
 
-        assert_eq!(trans.borrow().write_buffer_as_ref(), &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_large_sized_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::Map, 3928429);
 
         assert_success!(o_prot.write_set_begin(&ident));
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let res = assert_success!(i_prot.read_set_begin());
         assert_eq!(&res, &ident);
@@ -1950,53 +2235,58 @@
 
     #[test]
     fn must_write_zero_sized_map_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::String, TType::I32, 0)));
 
         let expected: [u8; 1] = [0x00]; // since size is zero we don't write anything
 
-        assert_eq!(trans.borrow().write_buffer_as_ref(), &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_read_zero_sized_map_begin() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Double, TType::I32, 0)));
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let res = assert_success!(i_prot.read_map_begin());
-        assert_eq!(&res,
-                   &TMapIdentifier {
-                       key_type: None,
-                       value_type: None,
-                       size: 0,
-                   });
+        assert_eq!(
+            &res,
+            &TMapIdentifier {
+                 key_type: None,
+                 value_type: None,
+                 size: 0,
+             }
+        );
     }
 
     #[test]
     fn must_write_map_begin() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Double, TType::String, 238)));
 
-        let expected: [u8; 3] = [0xEE, 0x01 /* size as varint */,
-                                 0x78 /* key type | val type */];
+        let expected: [u8; 3] = [
+            0xEE,
+            0x01, /* size as varint */
+            0x78 /* key type | val type */,
+        ];
 
-        assert_eq!(trans.borrow().write_buffer_as_ref(), &expected);
+        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::List, 1928349);
 
         assert_success!(o_prot.write_map_begin(&ident));
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         let res = assert_success!(i_prot.read_map_begin());
         assert_eq!(&res, &ident);
@@ -2009,23 +2299,26 @@
 
     #[test]
     fn must_write_map_with_bool_key_and_value() {
-        let (trans, _, mut o_prot) = test_objects();
+        let (_, mut o_prot) = test_objects();
 
         assert_success!(o_prot.write_map_begin(&TMapIdentifier::new(TType::Bool, TType::Bool, 1)));
         assert_success!(o_prot.write_bool(true));
         assert_success!(o_prot.write_bool(false));
         assert_success!(o_prot.write_map_end());
 
-        let expected: [u8; 4] = [0x01 /* size as varint */,
-                                 0x11 /* key type | val type */, 0x01 /* key: true */,
-                                 0x02 /* val: false */];
+        let expected: [u8; 4] = [
+            0x01, /* size as varint */
+            0x11, /* key type | val type */
+            0x01, /* key: true */
+            0x02 /* val: false */,
+        ];
 
-        assert_eq!(trans.borrow().write_buffer_as_ref(), &expected);
+        assert_eq_written_bytes!(o_prot, expected);
     }
 
     #[test]
     fn must_round_trip_map_with_bool_value() {
-        let (trans, mut i_prot, mut o_prot) = test_objects();
+        let (mut i_prot, mut o_prot) = test_objects();
 
         let map_ident = TMapIdentifier::new(TType::Bool, TType::Bool, 2);
         assert_success!(o_prot.write_map_begin(&map_ident));
@@ -2035,7 +2328,7 @@
         assert_success!(o_prot.write_bool(true));
         assert_success!(o_prot.write_map_end());
 
-        trans.borrow_mut().copy_write_buffer_to_read_buffer();
+        copy_write_buffer_to_read_buffer!(o_prot);
 
         // map header
         let rcvd_ident = assert_success!(i_prot.read_map_begin());
@@ -2058,28 +2351,30 @@
 
     #[test]
     fn must_read_map_end() {
-        let (_, mut i_prot, _) = test_objects();
+        let (mut i_prot, _) = test_objects();
         assert!(i_prot.read_map_end().is_ok()); // will blow up if we try to read from empty buffer
     }
 
-    fn test_objects<'a>
-        ()
-        -> (Rc<RefCell<Box<TBufferTransport>>>, TCompactInputProtocol<'a>, TCompactOutputProtocol<'a>)
+    fn test_objects()
+        -> (TCompactInputProtocol<ReadHalf<TBufferChannel>>,
+            TCompactOutputProtocol<WriteHalf<TBufferChannel>>)
     {
-        let mem = Rc::new(RefCell::new(Box::new(TBufferTransport::with_capacity(80, 80))));
+        let mem = TBufferChannel::with_capacity(80, 80);
 
-        let inner: Box<TTransport> = Box::new(TPassThruTransport { inner: mem.clone() });
-        let inner = Rc::new(RefCell::new(inner));
+        let (r_mem, w_mem) = mem.split().unwrap();
 
-        let i_prot = TCompactInputProtocol::new(inner.clone());
-        let o_prot = TCompactOutputProtocol::new(inner.clone());
+        let i_prot = TCompactInputProtocol::new(r_mem);
+        let o_prot = TCompactOutputProtocol::new(w_mem);
 
-        (mem, i_prot, o_prot)
+        (i_prot, o_prot)
     }
 
-    fn assert_no_write<F: FnMut(&mut TCompactOutputProtocol) -> ::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 TCompactOutputProtocol<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);
     }
 }
diff --git a/lib/rs/src/protocol/mod.rs b/lib/rs/src/protocol/mod.rs
index b230d63..4f13914 100644
--- a/lib/rs/src/protocol/mod.rs
+++ b/lib/rs/src/protocol/mod.rs
@@ -19,59 +19,77 @@
 //!
 //! # Examples
 //!
-//! Create and use a `TOutputProtocol`.
-//!
-//! ```no_run
-//! use std::cell::RefCell;
-//! use std::rc::Rc;
-//! use thrift::protocol::{TBinaryOutputProtocol, TFieldIdentifier, TOutputProtocol, TType};
-//! use thrift::transport::{TTcpTransport, TTransport};
-//!
-//! // create the I/O channel
-//! let mut transport = TTcpTransport::new();
-//! transport.open("127.0.0.1:9090").unwrap();
-//! let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
-//!
-//! // create the protocol to encode types into bytes
-//! let mut o_prot = TBinaryOutputProtocol::new(transport.clone(), true);
-//!
-//! // write types
-//! o_prot.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap();
-//! o_prot.write_string("foo").unwrap();
-//! o_prot.write_field_end().unwrap();
-//! ```
-//!
 //! Create and use a `TInputProtocol`.
 //!
 //! ```no_run
-//! use std::cell::RefCell;
-//! use std::rc::Rc;
 //! use thrift::protocol::{TBinaryInputProtocol, TInputProtocol};
-//! use thrift::transport::{TTcpTransport, TTransport};
+//! use thrift::transport::TTcpChannel;
 //!
 //! // create the I/O channel
-//! let mut transport = TTcpTransport::new();
-//! transport.open("127.0.0.1:9090").unwrap();
-//! let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
+//! let mut channel = TTcpChannel::new();
+//! channel.open("127.0.0.1:9090").unwrap();
 //!
 //! // create the protocol to decode bytes into types
-//! let mut i_prot = TBinaryInputProtocol::new(transport.clone(), true);
+//! let mut protocol = TBinaryInputProtocol::new(channel, true);
 //!
 //! // read types from the wire
-//! let field_identifier = i_prot.read_field_begin().unwrap();
-//! let field_contents = i_prot.read_string().unwrap();
-//! let field_end = i_prot.read_field_end().unwrap();
+//! let field_identifier = protocol.read_field_begin().unwrap();
+//! let field_contents = protocol.read_string().unwrap();
+//! let field_end = protocol.read_field_end().unwrap();
+//! ```
+//!
+//! Create and use a `TOutputProtocol`.
+//!
+//! ```no_run
+//! use thrift::protocol::{TBinaryOutputProtocol, TFieldIdentifier, TOutputProtocol, TType};
+//! use thrift::transport::TTcpChannel;
+//!
+//! // create the I/O channel
+//! let mut channel = TTcpChannel::new();
+//! channel.open("127.0.0.1:9090").unwrap();
+//!
+//! // create the protocol to encode types into bytes
+//! let mut protocol = TBinaryOutputProtocol::new(channel, true);
+//!
+//! // write types
+//! protocol.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap();
+//! protocol.write_string("foo").unwrap();
+//! protocol.write_field_end().unwrap();
 //! ```
 
-use std::cell::RefCell;
 use std::fmt;
 use std::fmt::{Display, Formatter};
 use std::convert::From;
-use std::rc::Rc;
 use try_from::TryFrom;
 
-use ::{ProtocolError, ProtocolErrorKind};
-use ::transport::TTransport;
+use {ProtocolError, ProtocolErrorKind};
+use transport::{TReadTransport, TWriteTransport};
+
+#[cfg(test)]
+macro_rules! assert_eq_written_bytes {
+    ($o_prot:ident, $expected_bytes:ident) => {
+        {
+            assert_eq!($o_prot.transport.write_bytes(), &$expected_bytes);
+        }
+    };
+}
+
+// FIXME: should take both read and write
+#[cfg(test)]
+macro_rules! copy_write_buffer_to_read_buffer {
+    ($o_prot:ident) => {
+        {
+            $o_prot.transport.copy_write_buffer_to_read_buffer();
+        }
+    };
+}
+
+#[cfg(test)]
+macro_rules! set_readable_bytes {
+    ($i_prot:ident, $bytes:expr) => {
+        $i_prot.transport.set_readable_bytes($bytes);
+    }
+}
 
 mod binary;
 mod compact;
@@ -107,20 +125,17 @@
 /// Create and use a `TInputProtocol`
 ///
 /// ```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("127.0.0.1:9090").unwrap();
-/// let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
+/// let mut channel = TTcpChannel::new();
+/// channel.open("127.0.0.1:9090").unwrap();
 ///
-/// let mut i_prot = TBinaryInputProtocol::new(transport.clone(), true);
+/// let mut protocol = TBinaryInputProtocol::new(channel, true);
 ///
-/// let field_identifier = i_prot.read_field_begin().unwrap();
-/// let field_contents = i_prot.read_string().unwrap();
-/// let field_end = i_prot.read_field_end().unwrap();
+/// let field_identifier = protocol.read_field_begin().unwrap();
+/// let field_contents = protocol.read_string().unwrap();
+/// let field_end = protocol.read_field_end().unwrap();
 /// ```
 pub trait TInputProtocol {
     /// Read the beginning of a Thrift message.
@@ -171,10 +186,14 @@
     /// Skip a field with type `field_type` recursively up to `depth` levels.
     fn skip_till_depth(&mut self, field_type: TType, depth: i8) -> ::Result<()> {
         if depth == 0 {
-            return Err(::Error::Protocol(ProtocolError {
-                kind: ProtocolErrorKind::DepthLimit,
-                message: format!("cannot parse past {:?}", field_type),
-            }));
+            return Err(
+                ::Error::Protocol(
+                    ProtocolError {
+                        kind: ProtocolErrorKind::DepthLimit,
+                        message: format!("cannot parse past {:?}", field_type),
+                    },
+                ),
+            );
         }
 
         match field_type {
@@ -213,9 +232,11 @@
             TType::Map => {
                 let map_ident = self.read_map_begin()?;
                 for _ in 0..map_ident.size {
-                    let key_type = map_ident.key_type
+                    let key_type = map_ident
+                        .key_type
                         .expect("non-zero sized map should contain key type");
-                    let val_type = map_ident.value_type
+                    let val_type = map_ident
+                        .value_type
                         .expect("non-zero sized map should contain value type");
                     self.skip_till_depth(key_type, depth - 1)?;
                     self.skip_till_depth(val_type, depth - 1)?;
@@ -223,10 +244,14 @@
                 self.read_map_end()
             }
             u => {
-                Err(::Error::Protocol(ProtocolError {
-                    kind: ProtocolErrorKind::Unknown,
-                    message: format!("cannot skip field type {:?}", &u),
-                }))
+                Err(
+                    ::Error::Protocol(
+                        ProtocolError {
+                            kind: ProtocolErrorKind::Unknown,
+                            message: format!("cannot skip field type {:?}", &u),
+                        },
+                    ),
+                )
             }
         }
     }
@@ -259,20 +284,17 @@
 /// Create and use a `TOutputProtocol`
 ///
 /// ```no_run
-/// use std::cell::RefCell;
-/// use std::rc::Rc;
 /// use thrift::protocol::{TBinaryOutputProtocol, TFieldIdentifier, TOutputProtocol, TType};
-/// use thrift::transport::{TTcpTransport, TTransport};
+/// use thrift::transport::TTcpChannel;
 ///
-/// let mut transport = TTcpTransport::new();
-/// transport.open("127.0.0.1:9090").unwrap();
-/// let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
+/// let mut channel = TTcpChannel::new();
+/// channel.open("127.0.0.1:9090").unwrap();
 ///
-/// let mut o_prot = TBinaryOutputProtocol::new(transport.clone(), true);
+/// let mut protocol = TBinaryOutputProtocol::new(channel, true);
 ///
-/// o_prot.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap();
-/// o_prot.write_string("foo").unwrap();
-/// o_prot.write_field_end().unwrap();
+/// protocol.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap();
+/// protocol.write_string("foo").unwrap();
+/// protocol.write_field_end().unwrap();
 /// ```
 pub trait TOutputProtocol {
     /// Write the beginning of a Thrift message.
@@ -330,6 +352,192 @@
     fn write_byte(&mut self, b: u8) -> ::Result<()>; // FIXME: REMOVE
 }
 
+impl<P> TInputProtocol for Box<P>
+where
+    P: TInputProtocol + ?Sized,
+{
+    fn read_message_begin(&mut self) -> ::Result<TMessageIdentifier> {
+        (**self).read_message_begin()
+    }
+
+    fn read_message_end(&mut self) -> ::Result<()> {
+        (**self).read_message_end()
+    }
+
+    fn read_struct_begin(&mut self) -> ::Result<Option<TStructIdentifier>> {
+        (**self).read_struct_begin()
+    }
+
+    fn read_struct_end(&mut self) -> ::Result<()> {
+        (**self).read_struct_end()
+    }
+
+    fn read_field_begin(&mut self) -> ::Result<TFieldIdentifier> {
+        (**self).read_field_begin()
+    }
+
+    fn read_field_end(&mut self) -> ::Result<()> {
+        (**self).read_field_end()
+    }
+
+    fn read_bool(&mut self) -> ::Result<bool> {
+        (**self).read_bool()
+    }
+
+    fn read_bytes(&mut self) -> ::Result<Vec<u8>> {
+        (**self).read_bytes()
+    }
+
+    fn read_i8(&mut self) -> ::Result<i8> {
+        (**self).read_i8()
+    }
+
+    fn read_i16(&mut self) -> ::Result<i16> {
+        (**self).read_i16()
+    }
+
+    fn read_i32(&mut self) -> ::Result<i32> {
+        (**self).read_i32()
+    }
+
+    fn read_i64(&mut self) -> ::Result<i64> {
+        (**self).read_i64()
+    }
+
+    fn read_double(&mut self) -> ::Result<f64> {
+        (**self).read_double()
+    }
+
+    fn read_string(&mut self) -> ::Result<String> {
+        (**self).read_string()
+    }
+
+    fn read_list_begin(&mut self) -> ::Result<TListIdentifier> {
+        (**self).read_list_begin()
+    }
+
+    fn read_list_end(&mut self) -> ::Result<()> {
+        (**self).read_list_end()
+    }
+
+    fn read_set_begin(&mut self) -> ::Result<TSetIdentifier> {
+        (**self).read_set_begin()
+    }
+
+    fn read_set_end(&mut self) -> ::Result<()> {
+        (**self).read_set_end()
+    }
+
+    fn read_map_begin(&mut self) -> ::Result<TMapIdentifier> {
+        (**self).read_map_begin()
+    }
+
+    fn read_map_end(&mut self) -> ::Result<()> {
+        (**self).read_map_end()
+    }
+
+    fn read_byte(&mut self) -> ::Result<u8> {
+        (**self).read_byte()
+    }
+}
+
+impl<P> TOutputProtocol for Box<P>
+where
+    P: TOutputProtocol + ?Sized,
+{
+    fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> {
+        (**self).write_message_begin(identifier)
+    }
+
+    fn write_message_end(&mut self) -> ::Result<()> {
+        (**self).write_message_end()
+    }
+
+    fn write_struct_begin(&mut self, identifier: &TStructIdentifier) -> ::Result<()> {
+        (**self).write_struct_begin(identifier)
+    }
+
+    fn write_struct_end(&mut self) -> ::Result<()> {
+        (**self).write_struct_end()
+    }
+
+    fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()> {
+        (**self).write_field_begin(identifier)
+    }
+
+    fn write_field_end(&mut self) -> ::Result<()> {
+        (**self).write_field_end()
+    }
+
+    fn write_field_stop(&mut self) -> ::Result<()> {
+        (**self).write_field_stop()
+    }
+
+    fn write_bool(&mut self, b: bool) -> ::Result<()> {
+        (**self).write_bool(b)
+    }
+
+    fn write_bytes(&mut self, b: &[u8]) -> ::Result<()> {
+        (**self).write_bytes(b)
+    }
+
+    fn write_i8(&mut self, i: i8) -> ::Result<()> {
+        (**self).write_i8(i)
+    }
+
+    fn write_i16(&mut self, i: i16) -> ::Result<()> {
+        (**self).write_i16(i)
+    }
+
+    fn write_i32(&mut self, i: i32) -> ::Result<()> {
+        (**self).write_i32(i)
+    }
+
+    fn write_i64(&mut self, i: i64) -> ::Result<()> {
+        (**self).write_i64(i)
+    }
+
+    fn write_double(&mut self, d: f64) -> ::Result<()> {
+        (**self).write_double(d)
+    }
+
+    fn write_string(&mut self, s: &str) -> ::Result<()> {
+        (**self).write_string(s)
+    }
+
+    fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()> {
+        (**self).write_list_begin(identifier)
+    }
+
+    fn write_list_end(&mut self) -> ::Result<()> {
+        (**self).write_list_end()
+    }
+
+    fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()> {
+        (**self).write_set_begin(identifier)
+    }
+
+    fn write_set_end(&mut self) -> ::Result<()> {
+        (**self).write_set_end()
+    }
+
+    fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()> {
+        (**self).write_map_begin(identifier)
+    }
+
+    fn write_map_end(&mut self) -> ::Result<()> {
+        (**self).write_map_end()
+    }
+
+    fn flush(&mut self) -> ::Result<()> {
+        (**self).flush()
+    }
+
+    fn write_byte(&mut self, b: u8) -> ::Result<()> {
+        (**self).write_byte(b)
+    }
+}
+
 /// Helper type used by servers to create `TInputProtocol` instances for
 /// accepted client connections.
 ///
@@ -338,21 +546,27 @@
 /// Create a `TInputProtocolFactory` and use it to create a `TInputProtocol`.
 ///
 /// ```no_run
-/// use std::cell::RefCell;
-/// use std::rc::Rc;
 /// use thrift::protocol::{TBinaryInputProtocolFactory, TInputProtocolFactory};
-/// use thrift::transport::{TTcpTransport, TTransport};
+/// use thrift::transport::TTcpChannel;
 ///
-/// let mut transport = TTcpTransport::new();
-/// transport.open("127.0.0.1:9090").unwrap();
-/// let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
+/// let mut channel = TTcpChannel::new();
+/// channel.open("127.0.0.1:9090").unwrap();
 ///
-/// let mut i_proto_factory = TBinaryInputProtocolFactory::new();
-/// let i_prot = i_proto_factory.create(transport);
+/// let factory = TBinaryInputProtocolFactory::new();
+/// let protocol = factory.create(Box::new(channel));
 /// ```
 pub trait TInputProtocolFactory {
-    /// Create a `TInputProtocol` that reads bytes from `transport`.
-    fn create(&mut self, transport: Rc<RefCell<Box<TTransport>>>) -> Box<TInputProtocol>;
+    // Create a `TInputProtocol` that reads bytes from `transport`.
+    fn create(&self, transport: Box<TReadTransport + Send>) -> Box<TInputProtocol + Send>;
+}
+
+impl<T> TInputProtocolFactory for Box<T>
+where
+    T: TInputProtocolFactory + ?Sized,
+{
+    fn create(&self, transport: Box<TReadTransport + Send>) -> Box<TInputProtocol + Send> {
+        (**self).create(transport)
+    }
 }
 
 /// Helper type used by servers to create `TOutputProtocol` instances for
@@ -363,21 +577,27 @@
 /// Create a `TOutputProtocolFactory` and use it to create a `TOutputProtocol`.
 ///
 /// ```no_run
-/// use std::cell::RefCell;
-/// use std::rc::Rc;
 /// use thrift::protocol::{TBinaryOutputProtocolFactory, TOutputProtocolFactory};
-/// use thrift::transport::{TTcpTransport, TTransport};
+/// use thrift::transport::TTcpChannel;
 ///
-/// let mut transport = TTcpTransport::new();
-/// transport.open("127.0.0.1:9090").unwrap();
-/// let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
+/// let mut channel = TTcpChannel::new();
+/// channel.open("127.0.0.1:9090").unwrap();
 ///
-/// let mut o_proto_factory = TBinaryOutputProtocolFactory::new();
-/// let o_prot = o_proto_factory.create(transport);
+/// let factory = TBinaryOutputProtocolFactory::new();
+/// let protocol = factory.create(Box::new(channel));
 /// ```
 pub trait TOutputProtocolFactory {
     /// Create a `TOutputProtocol` that writes bytes to `transport`.
-    fn create(&mut self, transport: Rc<RefCell<Box<TTransport>>>) -> Box<TOutputProtocol>;
+    fn create(&self, transport: Box<TWriteTransport + Send>) -> Box<TOutputProtocol + Send>;
+}
+
+impl<T> TOutputProtocolFactory for Box<T>
+where
+    T: TOutputProtocolFactory + ?Sized,
+{
+    fn create(&self, transport: Box<TWriteTransport + Send>) -> Box<TOutputProtocol + Send> {
+        (**self).create(transport)
+    }
 }
 
 /// Thrift message identifier.
@@ -394,10 +614,11 @@
 impl TMessageIdentifier {
     /// Create a `TMessageIdentifier` for a Thrift service-call named `name`
     /// with message type `message_type` and sequence number `sequence_number`.
-    pub fn new<S: Into<String>>(name: S,
-                                message_type: TMessageType,
-                                sequence_number: i32)
-                                -> TMessageIdentifier {
+    pub fn new<S: Into<String>>(
+        name: S,
+        message_type: TMessageType,
+        sequence_number: i32,
+    ) -> TMessageIdentifier {
         TMessageIdentifier {
             name: name.into(),
             message_type: message_type,
@@ -443,9 +664,10 @@
     ///
     /// `id` should be `None` if `field_type` is `TType::Stop`.
     pub fn new<N, S, I>(name: N, field_type: TType, id: I) -> TFieldIdentifier
-        where N: Into<Option<S>>,
-              S: Into<String>,
-              I: Into<Option<i16>>
+    where
+        N: Into<Option<S>>,
+        S: Into<String>,
+        I: Into<Option<i16>>,
     {
         TFieldIdentifier {
             name: name.into().map(|n| n.into()),
@@ -510,8 +732,9 @@
     /// Create a `TMapIdentifier` for a map with `size` entries of type
     /// `key_type -> value_type`.
     pub fn new<K, V>(key_type: K, value_type: V, size: i32) -> TMapIdentifier
-        where K: Into<Option<TType>>,
-              V: Into<Option<TType>>
+    where
+        K: Into<Option<TType>>,
+        V: Into<Option<TType>>,
     {
         TMapIdentifier {
             key_type: key_type.into(),
@@ -565,10 +788,14 @@
             0x03 => Ok(TMessageType::Exception),
             0x04 => Ok(TMessageType::OneWay),
             unkn => {
-                Err(::Error::Protocol(ProtocolError {
-                    kind: ProtocolErrorKind::InvalidData,
-                    message: format!("cannot convert {} to TMessageType", unkn),
-                }))
+                Err(
+                    ::Error::Protocol(
+                        ProtocolError {
+                            kind: ProtocolErrorKind::InvalidData,
+                            message: format!("cannot convert {} to TMessageType", unkn),
+                        },
+                    ),
+                )
             }
         }
     }
@@ -642,10 +869,14 @@
     if expected == actual {
         Ok(())
     } else {
-        Err(::Error::Application(::ApplicationError {
-            kind: ::ApplicationErrorKind::BadSequenceId,
-            message: format!("expected {} got {}", expected, actual),
-        }))
+        Err(
+            ::Error::Application(
+                ::ApplicationError {
+                    kind: ::ApplicationErrorKind::BadSequenceId,
+                    message: format!("expected {} got {}", expected, actual),
+                },
+            ),
+        )
     }
 }
 
@@ -657,10 +888,14 @@
     if expected == actual {
         Ok(())
     } else {
-        Err(::Error::Application(::ApplicationError {
-            kind: ::ApplicationErrorKind::WrongMethodName,
-            message: format!("expected {} got {}", expected, actual),
-        }))
+        Err(
+            ::Error::Application(
+                ::ApplicationError {
+                    kind: ::ApplicationErrorKind::WrongMethodName,
+                    message: format!("expected {} got {}", expected, actual),
+                },
+            ),
+        )
     }
 }
 
@@ -672,10 +907,14 @@
     if expected == actual {
         Ok(())
     } else {
-        Err(::Error::Application(::ApplicationError {
-            kind: ::ApplicationErrorKind::InvalidMessageType,
-            message: format!("expected {} got {}", expected, actual),
-        }))
+        Err(
+            ::Error::Application(
+                ::ApplicationError {
+                    kind: ::ApplicationErrorKind::InvalidMessageType,
+                    message: format!("expected {} got {}", expected, actual),
+                },
+            ),
+        )
     }
 }
 
@@ -686,10 +925,14 @@
     match *field {
         Some(_) => Ok(()),
         None => {
-            Err(::Error::Protocol(::ProtocolError {
-                kind: ::ProtocolErrorKind::Unknown,
-                message: format!("missing required field {}", field_name),
-            }))
+            Err(
+                ::Error::Protocol(
+                    ::ProtocolError {
+                        kind: ::ProtocolErrorKind::Unknown,
+                        message: format!("missing required field {}", field_name),
+                    },
+                ),
+            )
         }
     }
 }
@@ -700,10 +943,67 @@
 ///
 /// Return `TFieldIdentifier.id` if an id exists, `Err` otherwise.
 pub fn field_id(field_ident: &TFieldIdentifier) -> ::Result<i16> {
-    field_ident.id.ok_or_else(|| {
-        ::Error::Protocol(::ProtocolError {
-            kind: ::ProtocolErrorKind::Unknown,
-            message: format!("missing field in in {:?}", field_ident),
-        })
-    })
+    field_ident
+        .id
+        .ok_or_else(
+            || {
+                ::Error::Protocol(
+                    ::ProtocolError {
+                        kind: ::ProtocolErrorKind::Unknown,
+                        message: format!("missing field in in {:?}", field_ident),
+                    },
+                )
+            },
+        )
+}
+
+#[cfg(test)]
+mod tests {
+
+    use std::io::Cursor;
+
+    use super::*;
+    use transport::{TReadTransport, TWriteTransport};
+
+    #[test]
+    fn must_create_usable_input_protocol_from_concrete_input_protocol() {
+        let r: Box<TReadTransport> = Box::new(Cursor::new([0, 1, 2]));
+        let mut t = TCompactInputProtocol::new(r);
+        takes_input_protocol(&mut t)
+    }
+
+    #[test]
+    fn must_create_usable_input_protocol_from_boxed_input() {
+        let r: Box<TReadTransport> = Box::new(Cursor::new([0, 1, 2]));
+        let mut t: Box<TInputProtocol> = Box::new(TCompactInputProtocol::new(r));
+        takes_input_protocol(&mut t)
+    }
+
+    #[test]
+    fn must_create_usable_output_protocol_from_concrete_output_protocol() {
+        let w: Box<TWriteTransport> = Box::new(vec![0u8; 10]);
+        let mut t = TCompactOutputProtocol::new(w);
+        takes_output_protocol(&mut t)
+    }
+
+    #[test]
+    fn must_create_usable_output_protocol_from_boxed_output() {
+        let w: Box<TWriteTransport> = Box::new(vec![0u8; 10]);
+        let mut t: Box<TOutputProtocol> = Box::new(TCompactOutputProtocol::new(w));
+        takes_output_protocol(&mut t)
+    }
+
+    fn takes_input_protocol<R>(t: &mut R)
+    where
+        R: TInputProtocol,
+    {
+        t.read_byte().unwrap();
+    }
+
+    fn takes_output_protocol<W>(t: &mut W)
+    where
+        W: TOutputProtocol,
+    {
+        t.flush().unwrap();
+    }
 }
diff --git a/lib/rs/src/protocol/multiplexed.rs b/lib/rs/src/protocol/multiplexed.rs
index a30aca8..db08027 100644
--- a/lib/rs/src/protocol/multiplexed.rs
+++ b/lib/rs/src/protocol/multiplexed.rs
@@ -37,33 +37,37 @@
 /// Create and use a `TMultiplexedOutputProtocol`.
 ///
 /// ```no_run
-/// use std::cell::RefCell;
-/// use std::rc::Rc;
 /// use thrift::protocol::{TMessageIdentifier, TMessageType, TOutputProtocol};
 /// use thrift::protocol::{TBinaryOutputProtocol, TMultiplexedOutputProtocol};
-/// 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 o_prot = TBinaryOutputProtocol::new(transport, true);
-/// let mut o_prot = TMultiplexedOutputProtocol::new("service_name", Box::new(o_prot));
+/// let protocol = TBinaryOutputProtocol::new(channel, true);
+/// let mut protocol = TMultiplexedOutputProtocol::new("service_name", protocol);
 ///
 /// let ident = TMessageIdentifier::new("svc_call", TMessageType::Call, 1);
-/// o_prot.write_message_begin(&ident).unwrap();
+/// protocol.write_message_begin(&ident).unwrap();
 /// ```
-pub struct TMultiplexedOutputProtocol<'a> {
+#[derive(Debug)]
+pub struct TMultiplexedOutputProtocol<P>
+where
+    P: TOutputProtocol,
+{
     service_name: String,
-    inner: Box<TOutputProtocol + 'a>,
+    inner: P,
 }
 
-impl<'a> TMultiplexedOutputProtocol<'a> {
+impl<P> TMultiplexedOutputProtocol<P>
+where
+    P: TOutputProtocol,
+{
     /// Create a `TMultiplexedOutputProtocol` that identifies outgoing messages
     /// as originating from a service named `service_name` and sends them over
     /// the `wrapped` `TOutputProtocol`. Outgoing messages are encoded and sent
     /// by `wrapped`, not by this instance.
-    pub fn new(service_name: &str, wrapped: Box<TOutputProtocol + 'a>) -> TMultiplexedOutputProtocol<'a> {
+    pub fn new(service_name: &str, wrapped: P) -> TMultiplexedOutputProtocol<P> {
         TMultiplexedOutputProtocol {
             service_name: service_name.to_owned(),
             inner: wrapped,
@@ -72,7 +76,10 @@
 }
 
 // FIXME: avoid passthrough methods
-impl<'a> TOutputProtocol for TMultiplexedOutputProtocol<'a> {
+impl<P> TOutputProtocol for TMultiplexedOutputProtocol<P>
+where
+    P: TOutputProtocol,
+{
     fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()> {
         match identifier.message_type { // FIXME: is there a better way to override identifier here?
             TMessageType::Call | TMessageType::OneWay => {
@@ -181,39 +188,50 @@
 #[cfg(test)]
 mod tests {
 
-    use std::cell::RefCell;
-    use std::rc::Rc;
-
-    use ::protocol::{TBinaryOutputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol};
-    use ::transport::{TPassThruTransport, TTransport};
-    use ::transport::mem::TBufferTransport;
+    use protocol::{TBinaryOutputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol};
+    use transport::{TBufferChannel, TIoChannel, WriteHalf};
 
     use super::*;
 
     #[test]
     fn must_write_message_begin_with_prefixed_service_name() {
-        let (trans, mut o_prot) = test_objects();
+        let mut o_prot = test_objects();
 
         let ident = TMessageIdentifier::new("bar", TMessageType::Call, 2);
         assert_success!(o_prot.write_message_begin(&ident));
 
-        let expected: [u8; 19] =
-            [0x80, 0x01 /* protocol identifier */, 0x00, 0x01 /* message type */, 0x00,
-             0x00, 0x00, 0x07, 0x66, 0x6F, 0x6F /* "foo" */, 0x3A /* ":" */, 0x62, 0x61,
-             0x72 /* "bar" */, 0x00, 0x00, 0x00, 0x02 /* sequence number */];
+        let expected: [u8; 19] = [
+            0x80,
+            0x01, /* protocol identifier */
+            0x00,
+            0x01, /* message type */
+            0x00,
+            0x00,
+            0x00,
+            0x07,
+            0x66,
+            0x6F,
+            0x6F, /* "foo" */
+            0x3A, /* ":" */
+            0x62,
+            0x61,
+            0x72, /* "bar" */
+            0x00,
+            0x00,
+            0x00,
+            0x02 /* sequence number */,
+        ];
 
-        assert_eq!(&trans.borrow().write_buffer_to_vec(), &expected);
+        assert_eq!(o_prot.inner.transport.write_bytes(), expected);
     }
 
-    fn test_objects<'a>() -> (Rc<RefCell<Box<TBufferTransport>>>, TMultiplexedOutputProtocol<'a>) {
-        let mem = Rc::new(RefCell::new(Box::new(TBufferTransport::with_capacity(40, 40))));
-
-        let inner: Box<TTransport> = Box::new(TPassThruTransport { inner: mem.clone() });
-        let inner = Rc::new(RefCell::new(inner));
-
-        let o_prot = TBinaryOutputProtocol::new(inner.clone(), true);
-        let o_prot = TMultiplexedOutputProtocol::new("foo", Box::new(o_prot));
-
-        (mem, o_prot)
+    fn test_objects
+        ()
+        -> TMultiplexedOutputProtocol<TBinaryOutputProtocol<WriteHalf<TBufferChannel>>>
+    {
+        let c = TBufferChannel::with_capacity(40, 40);
+        let (_, w_chan) = c.split().unwrap();
+        let prot = TBinaryOutputProtocol::new(w_chan, true);
+        TMultiplexedOutputProtocol::new("foo", prot)
     }
 }
diff --git a/lib/rs/src/protocol/stored.rs b/lib/rs/src/protocol/stored.rs
index 6826c00..b3f305f 100644
--- a/lib/rs/src/protocol/stored.rs
+++ b/lib/rs/src/protocol/stored.rs
@@ -17,8 +17,8 @@
 
 use std::convert::Into;
 
-use ::ProtocolErrorKind;
-use super::{TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TInputProtocol,
+use ProtocolErrorKind;
+use super::{TFieldIdentifier, TInputProtocol, TListIdentifier, TMapIdentifier, TMessageIdentifier,
             TSetIdentifier, TStructIdentifier};
 
 /// `TInputProtocol` required to use a `TMultiplexedProcessor`.
@@ -40,35 +40,34 @@
 /// Create and use a `TStoredInputProtocol`.
 ///
 /// ```no_run
-/// use std::cell::RefCell;
-/// use std::rc::Rc;
 /// use thrift;
 /// use thrift::protocol::{TInputProtocol, TMessageIdentifier, TMessageType, TOutputProtocol};
 /// use thrift::protocol::{TBinaryInputProtocol, TBinaryOutputProtocol, TStoredInputProtocol};
 /// use thrift::server::TProcessor;
-/// use thrift::transport::{TTcpTransport, TTransport};
+/// use thrift::transport::{TIoChannel, TTcpChannel};
 ///
 /// // sample processor
 /// struct ActualProcessor;
 /// impl TProcessor for ActualProcessor {
 ///     fn process(
-///         &mut self,
+///         &self,
 ///         _: &mut TInputProtocol,
 ///         _: &mut TOutputProtocol
 ///     ) -> thrift::Result<()> {
 ///         unimplemented!()
 ///     }
 /// }
-/// let mut processor = ActualProcessor {};
+/// let processor = ActualProcessor {};
 ///
 /// // construct the shared transport
-/// 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 (i_chan, o_chan) = channel.split().unwrap();
 ///
 /// // construct the actual input and output protocols
-/// let mut i_prot = TBinaryInputProtocol::new(transport.clone(), true);
-/// let mut o_prot = TBinaryOutputProtocol::new(transport.clone(), true);
+/// let mut i_prot = TBinaryInputProtocol::new(i_chan, true);
+/// let mut o_prot = TBinaryOutputProtocol::new(o_chan, true);
 ///
 /// // message identifier received from remote and modified to remove the service name
 /// let new_msg_ident = TMessageIdentifier::new("service_call", TMessageType::Call, 1);
@@ -77,6 +76,7 @@
 /// let mut proxy_i_prot = TStoredInputProtocol::new(&mut i_prot, new_msg_ident);
 /// let res = processor.process(&mut proxy_i_prot, &mut o_prot);
 /// ```
+// FIXME: implement Debug
 pub struct TStoredInputProtocol<'a> {
     inner: &'a mut TInputProtocol,
     message_ident: Option<TMessageIdentifier>,
@@ -88,9 +88,10 @@
     /// `TInputProtocol`. `message_ident` is the modified message identifier -
     /// with service name stripped - that will be passed to
     /// `wrapped.read_message_begin(...)`.
-    pub fn new(wrapped: &mut TInputProtocol,
-               message_ident: TMessageIdentifier)
-               -> TStoredInputProtocol {
+    pub fn new(
+        wrapped: &mut TInputProtocol,
+        message_ident: TMessageIdentifier,
+    ) -> TStoredInputProtocol {
         TStoredInputProtocol {
             inner: wrapped,
             message_ident: message_ident.into(),
@@ -100,10 +101,16 @@
 
 impl<'a> TInputProtocol for TStoredInputProtocol<'a> {
     fn read_message_begin(&mut self) -> ::Result<TMessageIdentifier> {
-        self.message_ident.take().ok_or_else(|| {
-            ::errors::new_protocol_error(ProtocolErrorKind::Unknown,
-                                         "message identifier already read")
-        })
+        self.message_ident
+            .take()
+            .ok_or_else(
+                || {
+                    ::errors::new_protocol_error(
+                        ProtocolErrorKind::Unknown,
+                        "message identifier already read",
+                    )
+                },
+            )
     }
 
     fn read_message_end(&mut self) -> ::Result<()> {