about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-10-16 17:01:30 -0700
committerbors <bors@rust-lang.org>2013-10-16 17:01:30 -0700
commit63e097d8c34143411ea6d3146493bd6d8f3428d7 (patch)
tree0a266bf84cbfe54491e671445faa14d50bb67261 /src
parent9d6c251881584181a0022dc41832398af2136f19 (diff)
parent8163cb53903dd09e920b6267eba72793394b77d0 (diff)
auto merge of #9634 : blake2-ppc/rust/by-ref-iter, r=thestinger
std::iter: Introduce .by_ref() adaptor

Creates a wrapper around a mutable reference to the iterator.

This is useful to allow applying iterator adaptors while still
retaining ownership of the original iterator value.

Example::

    let mut xs = range(0, 10);
    // sum the first five values
    let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b);
    assert!(partial_sum == 10);
    // xs.next() is now `5`
    assert!(xs.next() == Some(5));

---

This adaptor requires the user to have good understanding of
iterators or what a particular adaptor does. There could be some
pitfalls here with the iterator protocol, it's mostly the same issues
as other places regarding what happens after the iterator
returns None for the first time.

There could also be other ways to achieve the same thing, for
example Implementing iterator on `&mut T` itself:
`impl <T: Iterator<..>> Iterator for &mut T`  but that would only
lead to confusion I think.
Diffstat (limited to 'src')
-rw-r--r--src/libstd/iter.rs44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs
index 08298889101..4d2abd2633f 100644
--- a/src/libstd/iter.rs
+++ b/src/libstd/iter.rs
@@ -405,6 +405,25 @@ pub trait Iterator<A> {
         Inspect{iter: self, f: f}
     }
 
+    /// Creates a wrapper around a mutable reference to the iterator.
+    ///
+    /// This is useful to allow applying iterator adaptors while still
+    /// retaining ownership of the original iterator value.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// let mut xs = range(0, 10);
+    /// // sum the first five values
+    /// let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b);
+    /// assert!(partial_sum == 10);
+    /// // xs.next() is now `5`
+    /// assert!(xs.next() == Some(5));
+    /// ```
+    fn by_ref<'r>(&'r mut self) -> ByRef<'r, Self> {
+        ByRef{iter: self}
+    }
+
     /// An adaptation of an external iterator to the for-loop protocol of rust.
     ///
     /// # Example
@@ -771,6 +790,22 @@ impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterato
     }
 }
 
+/// A mutable reference to an iterator
+pub struct ByRef<'self, T> {
+    priv iter: &'self mut T
+}
+
+impl<'self, A, T: Iterator<A>> Iterator<A> for ByRef<'self, T> {
+    #[inline]
+    fn next(&mut self) -> Option<A> { self.iter.next() }
+    // FIXME: #9629 we cannot implement &self methods like size_hint on ByRef
+}
+
+impl<'self, A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for ByRef<'self, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<A> { self.iter.next_back() }
+}
+
 /// A trait for iterators over elements which can be added together
 pub trait AdditiveIterator<A> {
     /// Iterates over the entire iterator, summing up all the elements
@@ -2501,6 +2536,15 @@ mod tests {
     }
 
     #[test]
+    fn test_by_ref() {
+        let mut xs = range(0, 10);
+        // sum the first five values
+        let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b);
+        assert_eq!(partial_sum, 10);
+        assert_eq!(xs.next(), Some(5));
+    }
+
+    #[test]
     fn test_invert() {
         let xs = [2, 4, 6, 8, 10, 12, 14, 16];
         let mut it = xs.iter();