From 4f8c56511193aee888cb45d24e199743aea844b9 Mon Sep 17 00:00:00 2001
From: Carl Lerche <me@carllerche.com>
Date: Wed, 1 Mar 2017 09:11:44 -0800
Subject: [PATCH] Implement `FromBuf` and `Buf::collect`

Enables collecting the contents of a `Buf` value into a relevant
concrete buffer implementation.
---
 src/buf/buf.rs         |  26 ++++++++-
 src/buf/from_buf.rs    | 117 +++++++++++++++++++++++++++++++++++++++++
 src/buf/mod.rs         |   2 +
 tests/test_from_buf.rs |  34 ++++++++++++
 4 files changed, 178 insertions(+), 1 deletion(-)
 create mode 100644 src/buf/from_buf.rs
 create mode 100644 tests/test_from_buf.rs

diff --git a/src/buf/buf.rs b/src/buf/buf.rs
index 9b1be36..0e66052 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 0000000..55f5cef
--- /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 75738c9..cfff1e8 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 0000000..216bf12
--- /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);
+}
-- 
GitLab