diff --git a/src/buf/byte.rs b/src/buf/byte.rs
index 314bdf61f99cc3570683177251181f299c9fa22e..920299f34a79727fb21bebc28e6f5b9b3232afc5 100644
--- a/src/buf/byte.rs
+++ b/src/buf/byte.rs
@@ -75,14 +75,14 @@ impl ByteBuf {
 
     /// Splits the buffer into two at the current read index.
     pub fn drain_read(&mut self) -> BytesMut {
-        let drained = self.mem.drain_to(self.rd);
+        let drained = self.mem.drain_to_mut(self.rd);
         self.rd = 0;
         drained
     }
 
     /// Splits the buffer into two at the given index.
     pub fn drain_to(&mut self, at: usize) -> BytesMut {
-        let drained = self.mem.drain_to(at);
+        let drained = self.mem.drain_to_mut(at);
 
         if at >= self.rd {
             self.rd = 0;
diff --git a/src/bytes.rs b/src/bytes.rs
index cacf0a4ba19ff85ad918ee10f18c46f3a16569fb..07b66383f531c4f2e75b0acd1caf8f967483d5bc 100644
--- a/src/bytes.rs
+++ b/src/bytes.rs
@@ -23,7 +23,7 @@ pub struct BytesMut {
 }
 
 struct Inner {
-    data: Data,
+    data: UnsafeCell<Data>,
 
     // If this pointer is set, then the the BytesMut is backed by an Arc
     arc: Cell<usize>,
@@ -62,6 +62,10 @@ const KIND_MASK: usize = 3;
 const KIND_INLINE: usize = 1;
 const KIND_STATIC: usize = 2;
 
+const INLINE_START_OFFSET: usize = 16;
+const INLINE_START_MASK: usize = 0xff << INLINE_START_OFFSET;
+const INLINE_LEN_OFFSET: usize = 8;
+const INLINE_LEN_MASK: usize = 0xff << INLINE_LEN_OFFSET;
 
 /*
  *
@@ -75,11 +79,11 @@ impl Bytes {
     pub fn new() -> Bytes {
         Bytes {
             inner: Inner {
-                data: Data {
+                data: UnsafeCell::new(Data {
                     ptr: ptr::null_mut(),
                     len: 0,
                     cap: 0,
-                },
+                }),
                 arc: Cell::new(0),
             }
         }
@@ -98,11 +102,11 @@ impl Bytes {
     pub fn from_static(bytes: &'static [u8]) -> Bytes {
         Bytes {
             inner: Inner {
-                data: Data {
+                data: UnsafeCell::new(Data {
                     ptr: bytes.as_ptr() as *mut u8,
                     len: bytes.len(),
                     cap: bytes.len(),
-                },
+                }),
                 arc: Cell::new(KIND_STATIC),
             }
         }
@@ -113,6 +117,12 @@ impl Bytes {
         self.inner.len()
     }
 
+    /// Returns the total byte capacity of this `Bytes`
+    #[inline]
+    pub fn capacity(&self) -> usize {
+        self.inner.capacity()
+    }
+
     /// Returns true if the value contains no bytes
     pub fn is_empty(&self) -> bool {
         self.inner.is_empty()
@@ -125,7 +135,7 @@ impl Bytes {
 
     /// Extracts a new `Bytes` referencing the bytes from range [start, end).
     pub fn slice(&self, start: usize, end: usize) -> Bytes {
-        let mut ret = self.clone();
+        let ret = self.clone();
 
         unsafe {
             ret.inner.set_end(end);
@@ -156,7 +166,7 @@ impl Bytes {
     /// # Panics
     ///
     /// Panics if `at > len`
-    pub fn split_off(&mut self, at: usize) -> Bytes {
+    pub fn split_off(&self, at: usize) -> Bytes {
         Bytes { inner: self.inner.split_off(at) }
     }
 
@@ -171,7 +181,7 @@ impl Bytes {
     /// # Panics
     ///
     /// Panics if `at > len`
-    pub fn drain_to(&mut self, at: usize) -> Bytes {
+    pub fn drain_to(&self, at: usize) -> Bytes {
         Bytes { inner: self.inner.drain_to(at) }
     }
 
@@ -281,11 +291,11 @@ impl BytesMut {
         if cap <= INLINE_CAP {
             BytesMut {
                 inner: Inner {
-                    data: Data {
+                    data: UnsafeCell::new(Data {
                         ptr: ptr::null_mut(),
                         len: 0,
                         cap: 0,
-                    },
+                    }),
                     arc: Cell::new(KIND_INLINE),
                 }
             }
@@ -305,10 +315,12 @@ impl BytesMut {
                 let mut data: [u8; INLINE_CAP] = mem::uninitialized();
                 data[0..len].copy_from_slice(b);
 
+                let a = KIND_INLINE | (len << INLINE_LEN_OFFSET);
+
                 BytesMut {
                     inner: Inner {
                         data: mem::transmute(data),
-                        arc: Cell::new(KIND_INLINE | (len << 2)),
+                        arc: Cell::new(a),
                     }
                 }
             }
@@ -347,28 +359,66 @@ impl BytesMut {
     /// Afterwards `self` contains elements `[0, at)`, and the returned
     /// `BytesMut` contains elements `[at, capacity)`.
     ///
-    /// This is an O(1) operation that just increases the reference count and
-    /// sets a few indexes.
+    /// This is an O(1) operation [1] that just increases the reference count
+    /// and sets a few indexes.
+    ///
+    /// [1] Inlined bytes are copied
+    ///
+    /// # Panics
+    ///
+    /// Panics if `at > capacity`
+    pub fn split_off(&self, at: usize) -> Bytes {
+        Bytes { inner: self.inner.split_off(at) }
+    }
+
+    /// Splits the bytes into two at the given index.
+    ///
+    /// Afterwards `self` contains elements `[0, at)`, and the returned
+    /// `BytesMut` contains elements `[at, capacity)`.
+    ///
+    /// This is an O(1) operation [1] that just increases the reference count
+    /// and sets a few indexes.
+    ///
+    /// [1] Inlined bytes are copied
     ///
     /// # Panics
     ///
     /// Panics if `at > capacity`
-    pub fn split_off(&mut self, at: usize) -> BytesMut {
+    pub fn split_off_mut(&mut self, at: usize) -> BytesMut {
         BytesMut { inner: self.inner.split_off(at) }
     }
 
+    /// Splits the buffer into two at the given index.
+    ///
+    /// Afterwards `self` contains elements `[at, len)`, and the returned `Bytes`
+    /// contains elements `[0, at)`.
+    ///
+    /// This is an O(1) operation [1] that just increases the reference count
+    /// and sets a few indexes.
+    ///
+    /// [1] Inlined bytes are copied.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `at > len`
+    pub fn drain_to(&self, at: usize) -> Bytes {
+        Bytes { inner: self.inner.drain_to(at) }
+    }
+
     /// Splits the buffer into two at the given index.
     ///
     /// Afterwards `self` contains elements `[at, len)`, and the returned `BytesMut`
     /// contains elements `[0, at)`.
     ///
-    /// This is an O(1) operation that just increases the reference count and
+    /// This is an O(1) operation [1] that just increases the reference count and
     /// sets a few indexes.
     ///
+    /// [1] Inlined bytes are copied.
+    ///
     /// # Panics
     ///
     /// Panics if `at > len`
-    pub fn drain_to(&mut self, at: usize) -> BytesMut {
+    pub fn drain_to_mut(&mut self, at: usize) -> BytesMut {
         BytesMut { inner: self.inner.drain_to(at) }
     }
 
@@ -418,10 +468,13 @@ impl Inner {
     fn as_ref(&self) -> &[u8] {
         if self.is_inline() {
             unsafe {
-                slice::from_raw_parts(&self.data as *const _ as *const u8, self.inline_len())
+                slice::from_raw_parts(self.inline_ptr(), self.inline_len())
             }
         } else {
-            unsafe { slice::from_raw_parts(self.data.ptr, self.data.len) }
+            unsafe {
+                let d = &*self.data.get();
+                slice::from_raw_parts(d.ptr, d.len)
+            }
         }
     }
 
@@ -431,10 +484,13 @@ impl Inner {
 
         if self.is_inline() {
             unsafe {
-                slice::from_raw_parts_mut(&mut self.data as *mut _ as *mut u8, self.inline_len())
+                slice::from_raw_parts_mut(self.inline_ptr(), self.inline_len())
             }
         } else {
-            unsafe { slice::from_raw_parts_mut(self.data.ptr, self.data.len) }
+            unsafe {
+                let d = &*self.data.get();
+                slice::from_raw_parts_mut(d.ptr, d.len)
+            }
         }
     }
 
@@ -443,9 +499,10 @@ impl Inner {
         debug_assert!(self.kind() != Kind::Static);
 
         if self.is_inline() {
-            slice::from_raw_parts_mut(&mut self.data as *mut _ as *mut u8, INLINE_CAP)
+            slice::from_raw_parts_mut(self.inline_ptr(), self.inline_capacity())
         } else {
-            slice::from_raw_parts_mut(self.data.ptr, self.data.cap)
+            let d = &*self.data.get();
+            slice::from_raw_parts_mut(d.ptr, d.cap)
         }
     }
 
@@ -454,23 +511,59 @@ impl Inner {
         if self.is_inline() {
             self.inline_len()
         } else {
-            self.data.len
+            unsafe { (*self.data.get()).len }
         }
     }
 
+    #[inline]
+    unsafe fn inline_ptr(&self) -> *mut u8 {
+        (self.data.get() as *mut u8).offset(self.inline_start() as isize)
+    }
+
+    #[inline]
+    fn inline_start(&self) -> usize {
+        (self.arc.get() & INLINE_START_MASK) >> INLINE_START_OFFSET
+    }
+
+    #[inline]
+    fn set_inline_start(&self, start: usize) {
+        debug_assert!(start <= INLINE_START_MASK);
+
+        let v = (self.arc.get() & !INLINE_START_MASK) |
+            (start << INLINE_START_OFFSET);
+
+        self.arc.set(v);
+    }
+
     #[inline]
     fn inline_len(&self) -> usize {
-        self.arc.get() >> 2
+        (self.arc.get() & INLINE_LEN_MASK) >> INLINE_LEN_OFFSET
+    }
+
+    #[inline]
+    fn set_inline_len(&self, len: usize) {
+        debug_assert!(len <= INLINE_LEN_MASK);
+
+        let v = (self.arc.get() & !INLINE_LEN_MASK) |
+            (len << INLINE_LEN_OFFSET);
+
+        self.arc.set(v);
+    }
+
+    #[inline]
+    fn inline_capacity(&self) -> usize {
+        INLINE_CAP - self.inline_start()
     }
 
     #[inline]
     unsafe fn set_len(&mut self, len: usize) {
         if self.is_inline() {
-            assert!(len <= INLINE_CAP);
-            self.arc.set(len << 2 | KIND_INLINE);
+            assert!(len <= self.inline_capacity());
+            self.set_inline_len(len);
         } else {
-            assert!(len <= self.data.cap);
-            self.data.len = len;
+            let d = &mut *self.data.get();
+            assert!(len <= d.cap);
+            d.len = len;
         }
     }
 
@@ -482,14 +575,14 @@ impl Inner {
     #[inline]
     pub fn capacity(&self) -> usize {
         if self.is_inline() {
-            INLINE_CAP
+            self.inline_capacity()
         } else {
-            self.data.cap
+            unsafe { (*self.data.get()).cap }
         }
     }
 
-    fn split_off(&mut self, at: usize) -> Inner {
-        let mut other = self.shallow_clone();
+    fn split_off(&self, at: usize) -> Inner {
+        let other = self.shallow_clone();
 
         unsafe {
             other.set_start(at);
@@ -499,8 +592,8 @@ impl Inner {
         return other
     }
 
-    fn drain_to(&mut self, at: usize) -> Inner {
-        let mut other = self.shallow_clone();
+    fn drain_to(&self, at: usize) -> Inner {
+        let other = self.shallow_clone();
 
         unsafe {
             other.set_end(at);
@@ -516,46 +609,41 @@ impl Inner {
     ///
     /// This method will panic if `start` is out of bounds for the underlying
     /// slice.
-    unsafe fn set_start(&mut self, start: usize) {
+    unsafe fn set_start(&self, start: usize) {
         debug_assert!(self.is_shared());
 
+        if start == 0 {
+            return;
+        }
+
         if self.is_inline() {
-            if start == 0 {
-                return;
-            }
+            assert!(start <= self.inline_capacity());
 
-            let len = self.inline_len();
+            let old_start = self.inline_start();
+            let old_len = self.inline_len();
 
-            if len <= start {
-                assert!(start <= INLINE_CAP);
+            self.set_inline_start(old_start + start);
 
-                // Set the length to zero
-                self.arc.set(KIND_INLINE);
+            if old_len >= start {
+                self.set_inline_len(old_len - start);
             } else {
-                debug_assert!(start <= INLINE_CAP);
-
-                let new_len = len - start;
-
-                let dst = &self.data as *const Data as *mut Data as *mut u8;
-                let src = (dst as *const u8).offset(start as isize);
-
-                ptr::copy(src, dst, new_len);
-
-                self.arc.set((new_len << 2) | KIND_INLINE);
+                self.set_inline_len(0);
             }
         } else {
-            assert!(start <= self.data.cap);
+            let d = &mut *self.data.get();
+
+            assert!(start <= d.cap);
 
-            self.data.ptr = self.data.ptr.offset(start as isize);
+            d.ptr = d.ptr.offset(start as isize);
 
             // TODO: This could probably be optimized with some bit fiddling
-            if self.data.len >= start {
-                self.data.len -= start;
+            if d.len >= start {
+                d.len -= start;
             } else {
-                self.data.len = 0;
+                d.len = 0;
             }
 
-            self.data.cap -= start;
+            d.cap -= start;
         }
     }
 
@@ -565,20 +653,20 @@ impl Inner {
     ///
     /// This method will panic if `start` is out of bounds for the underlying
     /// slice.
-    unsafe fn set_end(&mut self, end: usize) {
+    unsafe fn set_end(&self, end: usize) {
         debug_assert!(self.is_shared());
 
         if self.is_inline() {
-            assert!(end <= INLINE_CAP);
+            assert!(end <= self.inline_capacity());
             let new_len = cmp::min(self.inline_len(), end);
-
-            self.arc.set((new_len << 2) | KIND_INLINE);
+            self.set_inline_len(new_len);
         } else {
-            assert!(end <= self.data.cap);
-            debug_assert!(self.is_shared());
+            let d = &mut *self.data.get();
 
-            self.data.cap = end;
-            self.data.len = cmp::min(self.data.len, end);
+            assert!(end <= d.cap);
+
+            d.cap = end;
+            d.len = cmp::min(d.len, end);
         }
     }
 
@@ -603,17 +691,16 @@ impl Inner {
         match self.kind() {
             Kind::Vec => {
                 unsafe {
+                    let d = &*self.data.get();
+
                     // Promote this `Bytes` to an arc, and clone it
-                    let v = Vec::from_raw_parts(
-                        self.data.ptr,
-                        self.data.len,
-                        self.data.cap);
+                    let v = Vec::from_raw_parts(d.ptr, d.len, d.cap);
 
                     let a = Arc::new(v);
                     self.arc.set(mem::transmute(a.clone()));
 
                     Inner {
-                        data: self.data,
+                        data: UnsafeCell::new(*d),
                         arc: Cell::new(mem::transmute(a)),
                     }
                 }
@@ -623,14 +710,34 @@ impl Inner {
                     let arc: &Shared = mem::transmute(&self.arc);
 
                     Inner {
-                        data: self.data,
+                        data: UnsafeCell::new(*self.data.get()),
                         arc: Cell::new(mem::transmute(arc.clone())),
                     }
                 }
             }
-            Kind::Inline | Kind::Static => {
+            Kind::Inline => {
+                let len = self.inline_len();
+
+                unsafe {
+                    let mut data: Data = mem::uninitialized();
+
+                    let dst = &mut data as *mut _ as *mut u8;
+                    let src = self.inline_ptr();
+
+                    ptr::copy_nonoverlapping(src, dst, len);
+
+                    let mut a = KIND_INLINE;
+                    a |= len << INLINE_LEN_OFFSET;
+
+                    Inner {
+                        data: UnsafeCell::new(data),
+                        arc: Cell::new(a),
+                    }
+                }
+            }
+            Kind::Static => {
                 Inner {
-                    data: self.data,
+                    data: unsafe { UnsafeCell::new(*self.data.get()) },
                     arc: Cell::new(self.arc.get()),
                 }
             }
@@ -671,11 +778,9 @@ impl Drop for Inner {
         match self.kind() {
             Kind::Vec => {
                 unsafe {
+                    let d = *self.data.get();
                     // Not shared, manually free
-                    let _ = Vec::from_raw_parts(
-                        self.data.ptr,
-                        self.data.len,
-                        self.data.cap);
+                    let _ = Vec::from_raw_parts(d.ptr, d.len, d.cap);
                 }
             }
             Kind::Arc => {
@@ -736,11 +841,11 @@ impl From<Vec<u8>> for BytesMut {
 
         BytesMut {
             inner: Inner {
-                data: Data {
+                data: UnsafeCell::new(Data {
                     ptr: ptr,
                     len: len,
                     cap: cap,
-                },
+                }),
                 arc: Cell::new(0),
             },
         }
diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs
index fa869266e28f93a364bd403ce3795a66300a49b9..a87413258eb4e420e1469c407a5da8b6128e1d2a 100644
--- a/tests/test_bytes.rs
+++ b/tests/test_bytes.rs
@@ -2,6 +2,9 @@ extern crate bytes;
 
 use bytes::{Bytes, BytesMut};
 
+const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb";
+const SHORT: &'static [u8] = b"hello world";
+
 fn is_sync<T: Sync>() {}
 fn is_send<T: Send>() {}
 
@@ -93,7 +96,7 @@ fn slice_oob_2() {
 
 #[test]
 fn split_off() {
-    let mut hello = Bytes::from_slice(b"helloworld");
+    let hello = Bytes::from_slice(b"helloworld");
     let world = hello.split_off(5);
 
     assert_eq!(hello, &b"hello"[..]);
@@ -109,7 +112,7 @@ fn split_off() {
 #[test]
 #[should_panic]
 fn split_off_oob() {
-    let mut hello = Bytes::from_slice(b"helloworld");
+    let hello = Bytes::from_slice(b"helloworld");
     hello.split_off(25);
 }
 
@@ -133,24 +136,32 @@ fn split_off_uninitialized() {
 }
 
 #[test]
-fn drain_to() {
-    let mut world = Bytes::from_slice(b"helloworld");
-    let hello = world.drain_to(5);
+fn drain_to_1() {
+    // Inline
+    let a = Bytes::from_slice(SHORT);
+    let b = a.drain_to(4);
 
-    assert_eq!(hello, &b"hello"[..]);
-    assert_eq!(world, &b"world"[..]);
+    assert_eq!(SHORT[4..], a);
+    assert_eq!(SHORT[..4], b);
 
-    let mut world = BytesMut::from_slice(b"helloworld");
-    let hello = world.drain_to(5);
+    // Allocated
+    let a = Bytes::from_slice(LONG);
+    let b = a.drain_to(4);
 
-    assert_eq!(hello, &b"hello"[..]);
-    assert_eq!(world, &b"world"[..]);
+    assert_eq!(LONG[4..], a);
+    assert_eq!(LONG[..4], b);
+
+    let a = Bytes::from_slice(LONG);
+    let b = a.drain_to(30);
+
+    assert_eq!(LONG[30..], a);
+    assert_eq!(LONG[..30], b);
 }
 
 #[test]
 #[should_panic]
 fn drain_to_oob() {
-    let mut hello = Bytes::from_slice(b"helloworld");
+    let hello = Bytes::from_slice(b"helloworld");
     hello.drain_to(30);
 }