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); +}