From 8fec8a92ad8f554824ce51d554b495a8672b1072 Mon Sep 17 00:00:00 2001
From: Carl Lerche <me@carllerche.com>
Date: Wed, 1 Mar 2017 09:28:07 -0800
Subject: [PATCH] Implement iterator adapter for `Buf`

---
 src/buf/buf.rs  |  21 ++++++++-
 src/buf/iter.rs | 113 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/buf/mod.rs  |   2 +
 src/bytes.rs    |  39 ++++++++++++++++-
 4 files changed, 173 insertions(+), 2 deletions(-)
 create mode 100644 src/buf/iter.rs

diff --git a/src/buf/buf.rs b/src/buf/buf.rs
index 0e66052..c537e04 100644
--- a/src/buf/buf.rs
+++ b/src/buf/buf.rs
@@ -1,4 +1,4 @@
-use super::{Take, Reader, FromBuf};
+use super::{Take, Reader, Iter, FromBuf};
 use byteorder::ByteOrder;
 
 use std::{cmp, ptr};
@@ -546,4 +546,23 @@ pub trait Buf {
     fn reader(self) -> Reader<Self> where Self: Sized {
         super::reader::new(self)
     }
+
+    /// Returns an iterator over the bytes contained by the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use bytes::{Buf, IntoBuf, Bytes};
+    ///
+    /// let buf = Bytes::from(&b"abc"[..]).into_buf();
+    /// let mut iter = buf.iter();
+    ///
+    /// assert_eq!(iter.next(), Some(b'a'));
+    /// assert_eq!(iter.next(), Some(b'b'));
+    /// assert_eq!(iter.next(), Some(b'c'));
+    /// assert_eq!(iter.next(), None);
+    /// ```
+    fn iter(self) -> Iter<Self> where Self: Sized {
+        super::iter::new(self)
+    }
 }
diff --git a/src/buf/iter.rs b/src/buf/iter.rs
new file mode 100644
index 0000000..d9cf41f
--- /dev/null
+++ b/src/buf/iter.rs
@@ -0,0 +1,113 @@
+use Buf;
+
+/// Iterator over the bytes contained by the buffer.
+///
+/// This struct is created by the [`iter`] method on [`Buf`].
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use bytes::{Buf, IntoBuf, Bytes};
+///
+/// let buf = Bytes::from(&b"abc"[..]).into_buf();
+/// let mut iter = buf.iter();
+///
+/// assert_eq!(iter.next(), Some(b'a'));
+/// assert_eq!(iter.next(), Some(b'b'));
+/// assert_eq!(iter.next(), Some(b'c'));
+/// assert_eq!(iter.next(), None);
+/// ```
+///
+/// [`iter`]: trait.Buf.html#method.iter
+/// [`Buf`]: trait.Buf.html
+pub struct Iter<T> {
+    inner: T,
+}
+
+impl<T> Iter<T> {
+    /// Consumes this `Iter`, returning the underlying value.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::{Buf, IntoBuf, Bytes};
+    ///
+    /// let buf = Bytes::from(&b"abc"[..]).into_buf();
+    /// let mut iter = buf.iter();
+    ///
+    /// assert_eq!(iter.next(), Some(b'a'));
+    ///
+    /// let buf = iter.into_inner();
+    /// assert_eq!(2, buf.remaining());
+    /// ```
+    pub fn into_inner(self) -> T {
+        self.inner
+    }
+
+    /// Gets a reference to the underlying `Buf`.
+    ///
+    /// It is inadvisable to directly read from the underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::{Buf, IntoBuf, Bytes};
+    ///
+    /// let buf = Bytes::from(&b"abc"[..]).into_buf();
+    /// let mut iter = buf.iter();
+    ///
+    /// assert_eq!(iter.next(), Some(b'a'));
+    ///
+    /// assert_eq!(2, iter.get_ref().remaining());
+    /// ```
+    pub fn get_ref(&self) -> &T {
+        &self.inner
+    }
+
+    /// Gets a mutable reference to the underlying `Buf`.
+    ///
+    /// It is inadvisable to directly read from the underlying `Buf`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use bytes::{Buf, IntoBuf, BytesMut};
+    ///
+    /// let buf = BytesMut::from(&b"abc"[..]).into_buf();
+    /// let mut iter = buf.iter();
+    ///
+    /// assert_eq!(iter.next(), Some(b'a'));
+    ///
+    /// iter.get_mut().set_position(0);
+    ///
+    /// assert_eq!(iter.next(), Some(b'a'));
+    /// ```
+    pub fn get_mut(&mut self) -> &mut T {
+        &mut self.inner
+    }
+}
+
+pub fn new<T>(inner: T) -> Iter<T> {
+    Iter { inner: inner }
+}
+
+impl<T: Buf> Iterator for Iter<T> {
+    type Item = u8;
+
+    fn next(&mut self) -> Option<u8> {
+        if !self.inner.has_remaining() {
+            return None;
+        }
+
+        let b = self.inner.bytes()[0];
+        self.inner.advance(1);
+        Some(b)
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let rem = self.inner.remaining();
+        (rem, Some(rem))
+    }
+}
diff --git a/src/buf/mod.rs b/src/buf/mod.rs
index cfff1e8..ea83b5e 100644
--- a/src/buf/mod.rs
+++ b/src/buf/mod.rs
@@ -22,6 +22,7 @@ mod buf;
 mod buf_mut;
 mod from_buf;
 mod into_buf;
+mod iter;
 mod reader;
 mod source;
 mod take;
@@ -31,6 +32,7 @@ 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::iter::Iter;
 pub use self::reader::Reader;
 pub use self::source::Source;
 pub use self::take::Take;
diff --git a/src/bytes.rs b/src/bytes.rs
index 980e846..1ebcff1 100644
--- a/src/bytes.rs
+++ b/src/bytes.rs
@@ -1,4 +1,5 @@
-use {IntoBuf, BufMut};
+use {IntoBuf, Buf, BufMut};
+use buf::Iter;
 
 use std::{cmp, fmt, mem, hash, ops, slice, ptr, usize};
 use std::borrow::Borrow;
@@ -733,6 +734,24 @@ impl Borrow<[u8]> for Bytes {
     }
 }
 
+impl IntoIterator for Bytes {
+    type Item = u8;
+    type IntoIter = Iter<Cursor<Bytes>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.into_buf().iter()
+    }
+}
+
+impl<'a> IntoIterator for &'a Bytes {
+    type Item = u8;
+    type IntoIter = Iter<Cursor<&'a Bytes>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.into_buf().iter()
+    }
+}
+
 /*
  *
  * ===== BytesMut =====
@@ -1286,6 +1305,24 @@ impl Clone for BytesMut {
     }
 }
 
+impl IntoIterator for BytesMut {
+    type Item = u8;
+    type IntoIter = Iter<Cursor<BytesMut>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.into_buf().iter()
+    }
+}
+
+impl<'a> IntoIterator for &'a BytesMut {
+    type Item = u8;
+    type IntoIter = Iter<Cursor<&'a BytesMut>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.into_buf().iter()
+    }
+}
+
 /*
  *
  * ===== Inner =====
-- 
GitLab