diff --git a/src/buf/buf.rs b/src/buf/buf.rs
index 9b1be36b5a79804cbe2f3d31a9e9595145a2ad4b..0e660521fda9d82949af6cd4f95c72ad89d15634 100644
--- a/src/buf/buf.rs
+++ b/src/buf/buf.rs
@@ -1,4 +1,4 @@
-use super::{Take, Reader};
+use super::{Take, Reader, FromBuf};
 use byteorder::ByteOrder;
 
 use std::{cmp, ptr};
@@ -441,6 +441,30 @@ pub trait Buf {
         T::read_f64(&buf)
     }
 
+    /// Transforms a `Buf` into a concrete buffer.
+    ///
+    /// `collect()` can operate on any value that implements `Buf`, and turn it
+    /// into the relevent concrete buffer type.
+    ///
+    /// # Examples
+    ///
+    /// Collecting a buffer and loading the contents into a `Vec<u8>`.
+    ///
+    /// ```
+    /// use bytes::{Buf, Bytes, IntoBuf};
+    ///
+    /// let buf = Bytes::from(&b"hello world"[..]).into_buf();
+    /// let vec: Vec<u8> = buf.collect();
+    ///
+    /// assert_eq!(vec, &b"hello world"[..]);
+    /// ```
+    fn collect<B>(self) -> B
+        where Self: Sized,
+              B: FromBuf,
+    {
+        B::from_buf(self)
+    }
+
     /// Creates an adaptor which will read at most `limit` bytes from `self`.
     ///
     /// This function returns a new instance of `Buf` which will read at most
diff --git a/src/buf/from_buf.rs b/src/buf/from_buf.rs
new file mode 100644
index 0000000000000000000000000000000000000000..55f5cef31b9043fd7cea86a32e11c57396b9b47d
--- /dev/null
+++ b/src/buf/from_buf.rs
@@ -0,0 +1,117 @@
+use {Buf, BufMut, IntoBuf, Bytes, BytesMut};
+
+/// Conversion from a [`Buf`]
+///
+/// Implementing `FromBuf` for a type defines how it is created from a buffer.
+/// This is common for types which represent byte storage of some kind.
+///
+/// [`FromBuf::from_buf`] is rarely called explicitly, and it is instead used
+/// through [`Buf::collect`]. See [`Buf::collect`] documentation for more examples.
+///
+/// See also [`IntoBuf`].
+///
+/// # Examples
+///
+/// Basic  usage:
+///
+/// ```
+/// use bytes::{Bytes, IntoBuf};
+/// use bytes::buf::FromBuf;
+///
+/// let buf = Bytes::from(&b"hello world"[..]).into_buf();
+/// let vec = Vec::from_buf(buf);
+///
+/// assert_eq!(vec, &b"hello world"[..]);
+/// ```
+///
+/// Using [`Buf::collect`] to implicitly use `FromBuf`:
+///
+/// ```
+/// use bytes::{Buf, Bytes, IntoBuf};
+///
+/// let buf = Bytes::from(&b"hello world"[..]).into_buf();
+/// let vec: Vec<u8> = buf.collect();
+///
+/// assert_eq!(vec, &b"hello world"[..]);
+/// ```
+///
+/// Implementing `FromBuf` for your type:
+///
+/// ```
+/// use bytes::{BufMut, Bytes};
+/// use bytes::buf::{IntoBuf, FromBuf};
+///
+/// // A sample buffer, that's just a wrapper over Vec<u8>
+/// struct MyBuffer(Vec<u8>);
+///
+/// impl FromBuf for MyBuffer {
+///     fn from_buf<B>(buf: B) -> Self where B: IntoBuf {
+///         let mut v = Vec::new();
+///         v.put(buf.into_buf());
+///         MyBuffer(v)
+///     }
+/// }
+///
+/// // Now we can make a new buf
+/// let buf = Bytes::from(&b"hello world"[..]);
+///
+/// // And make a MyBuffer out of it
+/// let my_buf = MyBuffer::from_buf(buf);
+///
+/// assert_eq!(my_buf.0, &b"hello world"[..]);
+/// ```
+///
+/// [`Buf`]: trait.Buf.html
+/// [`FromBuf::from_buf`]: #method.from_buf
+/// [`Buf::collect`]: trait.Buf.html#method.collect
+/// [`IntoBuf`]: trait.IntoBuf.html
+pub trait FromBuf {
+    /// Creates a value from a buffer.
+    ///
+    /// See the [type-level documentation](#) for more details.
+    ///
+    /// # Examples
+    ///
+    /// Basic  usage:
+    ///
+    /// ```
+    /// use bytes::{Bytes, IntoBuf};
+    /// use bytes::buf::FromBuf;
+    ///
+    /// let buf = Bytes::from(&b"hello world"[..]).into_buf();
+    /// let vec = Vec::from_buf(buf);
+    ///
+    /// assert_eq!(vec, &b"hello world"[..]);
+    /// ```
+    fn from_buf<T>(buf: T) -> Self where T: IntoBuf;
+}
+
+impl FromBuf for Vec<u8> {
+    fn from_buf<T>(buf: T) -> Self
+        where T: IntoBuf
+    {
+        let buf = buf.into_buf();
+        let mut ret = Vec::with_capacity(buf.remaining());
+        ret.put(buf);
+        ret
+    }
+}
+
+impl FromBuf for Bytes {
+    fn from_buf<T>(buf: T) -> Self
+        where T: IntoBuf
+    {
+        BytesMut::from_buf(buf).freeze()
+    }
+}
+
+impl FromBuf for BytesMut {
+    fn from_buf<T>(buf: T) -> Self
+        where T: IntoBuf
+    {
+        let buf = buf.into_buf();
+        let mut ret = BytesMut::with_capacity(buf.remaining());
+        ret.put(buf);
+        ret
+    }
+}
diff --git a/src/buf/mod.rs b/src/buf/mod.rs
index 75738c9954a9a120fb867b4b79553eb667b74e74..cfff1e8cac66d783283afd998e9a2dd07d842a95 100644
--- a/src/buf/mod.rs
+++ b/src/buf/mod.rs
@@ -20,6 +20,7 @@ use std::{cmp, io, usize};
 
 mod buf;
 mod buf_mut;
+mod from_buf;
 mod into_buf;
 mod reader;
 mod source;
@@ -28,6 +29,7 @@ mod writer;
 
 pub use self::buf::Buf;
 pub use self::buf_mut::BufMut;
+pub use self::from_buf::FromBuf;
 pub use self::into_buf::IntoBuf;
 pub use self::reader::Reader;
 pub use self::source::Source;
diff --git a/tests/test_from_buf.rs b/tests/test_from_buf.rs
new file mode 100644
index 0000000000000000000000000000000000000000..216bf1232805fa54eb3d9dd45edc55ed413b8eaa
--- /dev/null
+++ b/tests/test_from_buf.rs
@@ -0,0 +1,34 @@
+extern crate bytes;
+
+use bytes::{Buf, Bytes, BytesMut};
+use std::io::Cursor;
+
+const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb";
+const SHORT: &'static [u8] = b"hello world";
+
+#[test]
+fn collect_to_vec() {
+    let buf: Vec<u8> = Cursor::new(SHORT).collect();
+    assert_eq!(buf, SHORT);
+
+    let buf: Vec<u8> = Cursor::new(LONG).collect();
+    assert_eq!(buf, LONG);
+}
+
+#[test]
+fn collect_to_bytes() {
+    let buf: Bytes = Cursor::new(SHORT).collect();
+    assert_eq!(buf, SHORT);
+
+    let buf: Bytes = Cursor::new(LONG).collect();
+    assert_eq!(buf, LONG);
+}
+
+#[test]
+fn collect_to_bytes_mut() {
+    let buf: BytesMut = Cursor::new(SHORT).collect();
+    assert_eq!(buf, SHORT);
+
+    let buf: BytesMut = Cursor::new(LONG).collect();
+    assert_eq!(buf, LONG);
+}