Repository: bluss/rust-itertools
Pull request #310 (2018-10-03 00:03:18)

Add exactly_one function
Adds a small function I found uses for personally.  Can't be added to the core library because in the error case it allocates a vec and stores data in it.


Patch:
diff --git a/.travis.yml b/.travis.yml
index faa6d94..31817e4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,14 @@ language: rust
 sudo: false
 matrix:
   include:
-    - rust: 1.22.0
+    - rust: 1.13.0
+      before_script:
+        # rand 0.4.2 requires rust 1.15, and rand-0.3.22 requires rand-0.4  :/
+        # manually hacking the lockfile due to the limitations of cargo#2773
+        - cargo generate-lockfile
+        - sed -i -e 's/"rand 0.[34].[0-9]\+/"rand 0.3.20/' Cargo.lock
+        - sed -i -e '/^name = "rand"/,/^$/s/version = "0.3.[0-9]\+"/version = "0.3.20"/' Cargo.lock
+    - rust: 1.15.0
     - rust: stable
     - rust: beta
     - rust: nightly
diff --git a/Cargo.toml b/Cargo.toml
index bc9b189..a4fed5b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "itertools"
-version = "0.7.11"
+version = "0.7.8"
 
 license = "MIT/Apache-2.0"
 repository = "https://github.com/bluss/rust-itertools"
@@ -11,7 +11,6 @@ description = "Extra iterator adaptors, iterator methods, free functions, and ma
 
 keywords = ["iterator", "data-structure", "zip", "product", "group-by"]
 categories = ["algorithms", "rust-patterns"]
-exclude = ["/bors.toml"]
 
 [lib]
 bench = false
@@ -20,11 +19,8 @@ test = false
 [dependencies]
 either = { version = "1.0", default-features = false }
 
-[dev-dependencies]
-rand = "0.6"
-
 [dev-dependencies.quickcheck]
-version = "0.7"
+version = "0.5"
 default-features = false
 
 [dev-dependencies.permutohedron]
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..bb03984
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,34 @@
+DOCCRATES = itertools
+
+# deps to delete the generated docs
+RMDOCS =
+
+FEATURES =
+
+VERSIONS = $(patsubst %,target/VERS/%,$(DOCCRATES))
+
+docs: mkdocs subst $(RMDOCS)
+
+# https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
+$(VERSIONS): Cargo.toml
+	mkdir -p $(@D)
+	cargo pkgid $(@F) | sed -e "s/.*#\(\|.*:\)//" > "$@"
+
+$(DOCCRATES): %: target/VERS/%
+	# Put in the crate version into the docs
+	find ./doc/$@ -name "*.html" -exec sed -i -e "s/<title>\(.*\) - Rust/<title>$@ $(shell cat $<) - \1 - Rust/g" {} \;
+
+subst: $(DOCCRATES)
+
+mkdocs: Cargo.toml
+	cargo doc --features=$(FEATURES) --no-deps
+	rm -rf ./doc
+	cp -r ./target/doc ./doc
+	- cat ./custom.css >> doc/main.css
+
+$(RMDOCS): mkdocs
+	rm -r ./doc/$@
+	sed -i "/searchIndex\['$@'\]/d" doc/search-index.js
+
+
+.PHONY: docs mkdocs subst $(DOCCRATES) $(RMDOCS)
diff --git a/README.rst b/README.rst
index bef5aa3..15fe2a3 100644
--- a/README.rst
+++ b/README.rst
@@ -21,7 +21,7 @@ How to use with cargo:
 .. code:: toml
 
     [dependencies]
-    itertools = "0.7"
+    itertools = "0.7.3"
 
 How to use in your crate:
 
@@ -48,21 +48,6 @@ then it can't be accepted into ``libcore``, and you should propose it for ``iter
 Recent Changes
 --------------
 
-- 0.7.11
-
-  - Add convenience methods to ``EitherOrBoth``, making it more similar to ``Option``
-    and ``Either`` by @jethrogb
-
-- 0.7.10
-
-  - No changes.
-
-- 0.7.9
-
-  - New inclusion policy: See the readme about suggesting features for std before
-    accepting them in itertools.
-  - The ``FoldWhile`` type now implements ``Eq`` and ``PartialEq`` by @jturner314
-
 - 0.7.8
 
   - Add new iterator method ``.tree_fold1()`` which is like ``.fold1()``
diff --git a/benches/tuple_combinations.rs b/benches/tuple_combinations.rs
index 4a14b1d..1f9075d 100644
--- a/benches/tuple_combinations.rs
+++ b/benches/tuple_combinations.rs
@@ -6,7 +6,7 @@ extern crate itertools;
 use test::{black_box, Bencher};
 use itertools::Itertools;
 
-// approximate 100_000 iterations for each combination
+// aproximate 100_000 iterations for each combination
 const N1: usize = 100_000;
 const N2: usize = 448;
 const N3: usize = 86;
diff --git a/custom.css b/custom.css
new file mode 100644
index 0000000..bd4b11e
--- /dev/null
+++ b/custom.css
@@ -0,0 +1,29 @@
+
+.docblock pre.rust { background: #eeeeff; }
+pre.trait, pre.fn, pre.struct, pre.enum, pre.typedef { background: #fcfefc; }
+
+/* Small “example” label for doc examples */
+.docblock pre.rust::before {
+    content: "example";
+    float: right;
+    font-style: italic;
+    font-size: 0.8em;
+    margin-top: -10px;
+    margin-right: -5px;
+}
+
+
+/* Fixup where display in trait listing */
+pre.trait .where::before {
+content: '\a         ';
+}
+
+.docblock code {
+    background-color: inherit;
+    font-weight: bold;
+    padding: 0 0.1em;
+}
+
+a.test-arrow {
+    display: none;
+}
diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs
index ba29636..eb1704f 100644
--- a/src/adaptors/mod.rs
+++ b/src/adaptors/mod.rs
@@ -13,6 +13,7 @@ use std::mem::replace;
 use std::iter::{Fuse, Peekable, FromIterator};
 use std::marker::PhantomData;
 use size_hint;
+use fold;
 
 macro_rules! clone_fields {
     ($name:ident, $base:expr, $($field:ident),+) => (
@@ -407,8 +408,6 @@ impl<B, F, I> Iterator for Batching<I, F>
 /// then skipping forward *n-1* elements.
 ///
 /// See [`.step()`](../trait.Itertools.html#method.step) for more information.
-#[deprecated(note="Use std .step_by() instead", since="0.8")]
-#[allow(deprecated)]
 #[derive(Clone, Debug)]
 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
 pub struct Step<I> {
@@ -419,7 +418,6 @@ pub struct Step<I> {
 /// Create a `Step` iterator.
 ///
 /// **Panics** if the step is 0.
-#[allow(deprecated)]
 pub fn step<I>(iter: I, step: usize) -> Step<I>
     where I: Iterator
 {
@@ -430,7 +428,6 @@ pub fn step<I>(iter: I, step: usize) -> Step<I>
     }
 }
 
-#[allow(deprecated)]
 impl<I> Iterator for Step<I>
     where I: Iterator
 {
@@ -458,7 +455,6 @@ impl<I> Iterator for Step<I>
 }
 
 // known size
-#[allow(deprecated)]
 impl<I> ExactSizeIterator for Step<I>
     where I: ExactSizeIterator
 {}
@@ -1039,6 +1035,81 @@ impl_tuple_combination!(Tuple3Combination Tuple2Combination ; A, A, A, A ; a b);
 impl_tuple_combination!(Tuple4Combination Tuple3Combination ; A, A, A, A, A; a b c);
 
 
+/// An iterator adapter to simply flatten a structure.
+///
+/// See [`.flatten()`](../trait.Itertools.html#method.flatten) for more information.
+#[derive(Clone, Debug)]
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+pub struct Flatten<I, J> {
+    iter: I,
+    front: Option<J>,
+}
+
+/// Flatten an iterable of iterables into a single combined sequence of all
+/// the elements in the iterables.
+///
+/// This is more or less equivalent to `.flat_map` with an identity
+/// function.
+///
+/// This is an `IntoIterator`-enabled version of the [`.flatten()`][1] adaptor.
+///
+/// [1]: trait.Itertools.html#method.flatten
+///
+/// ```
+/// use itertools::flatten;
+///
+/// let data = vec![vec![1, 2, 3], vec![4, 5, 6]];
+///
+/// itertools::assert_equal(flatten(&data),
+///                         &[1, 2, 3, 4, 5, 6]);
+/// ```
+pub fn flatten<I, J>(iterable: I) -> Flatten<I::IntoIter, J>
+    where I: IntoIterator,
+          I::Item: IntoIterator<IntoIter=J, Item=J::Item>,
+          J: Iterator,
+{
+    Flatten {
+        iter: iterable.into_iter(),
+        front: None,
+    }
+}
+
+impl<I, J> Iterator for Flatten<I, J>
+    where I: Iterator,
+          I::Item: IntoIterator<IntoIter=J, Item=J::Item>,
+          J: Iterator,
+{
+    type Item = J::Item;
+    fn next(&mut self) -> Option<Self::Item> {
+        loop {
+            if let Some(ref mut f) = self.front {
+                match f.next() {
+                    elt @ Some(_) => return elt,
+                    None => { }
+                }
+            }
+            if let Some(next_front) = self.iter.next() {
+                self.front = Some(next_front.into_iter());
+            } else {
+                break;
+            }
+        }
+        None
+    }
+
+    // special case to convert segmented iterator into consecutive loops
+    fn fold<Acc, G>(self, init: Acc, mut f: G) -> Acc
+        where G: FnMut(Acc, Self::Item) -> Acc,
+    {
+        let mut accum = init;
+        if let Some(iter) = self.front {
+            accum = fold(iter, accum, &mut f);
+        }
+        self.iter.fold(accum, move |accum, iter| fold(iter, accum, &mut f))
+    }
+
+}
+
 /// An iterator adapter to apply a transformation within a nested `Result`.
 ///
 /// See [`.map_results()`](../trait.Itertools.html#method.map_results) for more information.
diff --git a/src/either_or_both.rs b/src/either_or_both.rs
index 55ae06c..9f0f313 100644
--- a/src/either_or_both.rs
+++ b/src/either_or_both.rs
@@ -1,5 +1,3 @@
-use EitherOrBoth::*;
-
 /// Value that either holds a single A or B, or both.
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub enum EitherOrBoth<A, B> {
@@ -10,49 +8,3 @@ pub enum EitherOrBoth<A, B> {
     /// Only the right value of type `B` is present.
     Right(B),
 }
-
-impl<A, B> EitherOrBoth<A, B> {
-    /// If `Left`, or `Both`, return true, otherwise, return false.
-    pub fn has_left(&self) -> bool {
-        self.as_ref().left().is_some()
-    }
-
-    /// If `Right`, or `Both`, return true, otherwise, return false.
-    pub fn has_right(&self) -> bool {
-        self.as_ref().right().is_some()
-    }
-
-    /// If `Left`, or `Both`, return `Some` with the left value, otherwise, return `None`.
-    pub fn left(self) -> Option<A> {
-        match self {
-            Left(left) | Both(left, _) => Some(left),
-            _ => None
-        }
-    }
-
-    /// If `Right`, or `Both`, return `Some` with the right value, otherwise, return `None`.
-    pub fn right(self) -> Option<B> {
-        match self {
-            Right(right) | Both(_, right) => Some(right),
-            _ => None
-        }
-    }
-
-    /// Converts from `&EitherOrBoth<A, B>` to `EitherOrBoth<&A, &B>`.
-    pub fn as_ref(&self) -> EitherOrBoth<&A, &B> {
-        match *self {
-            Left(ref left) => Left(left),
-            Right(ref right) => Right(right),
-            Both(ref left, ref right) => Both(left, right),
-        }
-    }
-
-    /// Converts from `&mut EitherOrBoth<A, B>` to `EitherOrBoth<&mut A, &mut B>`.
-    pub fn as_mut(&mut self) -> EitherOrBoth<&mut A, &mut B> {
-        match *self {
-            Left(ref mut left) => Left(left),
-            Right(ref mut right) => Right(right),
-            Both(ref mut left, ref mut right) => Both(left, right),
-        }
-    }
-}
diff --git a/src/exactly_one_err.rs b/src/exactly_one_err.rs
new file mode 100644
index 0000000..51cfbc3
--- /dev/null
+++ b/src/exactly_one_err.rs
@@ -0,0 +1,58 @@
+use std::iter::ExactSizeIterator;
+
+use size_hint;
+
+/// Iterator returned for the error case of `IterTools::exactly_one()`
+/// This iterator yields exactly the same elements as the input iterator.
+///
+/// During the execution of exactly_one the iterator must be mutated.  This wrapper
+/// effectively "restores" the state of the input iterator when it's handed back.
+///
+/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not
+/// use a `Vec`.
+#[derive(Debug, Clone)]
+pub struct ExactlyOneError<I>
+where
+    I: Iterator,
+{
+    first_two: (Option<I::Item>, Option<I::Item>),
+    inner: I,
+}
+
+impl<I> ExactlyOneError<I>
+where
+    I: Iterator,
+{
+    /// Creates a new `ExactlyOneErr` iterator.
+    pub fn new(first_two: (Option<I::Item>, Option<I::Item>), inner: I) -> Self {
+        Self { first_two, inner }
+    }
+}
+
+impl<I> Iterator for ExactlyOneError<I>
+where
+    I: Iterator,
+{
+    type Item = I::Item;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.first_two
+            .0
+            .take()
+            .or_else(|| self.first_two.1.take())
+            .or_else(|| self.inner.next())
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let mut additional_len = 0;
+        if self.first_two.0.is_some() {
+            additional_len += 1;
+        }
+        if self.first_two.1.is_some() {
+            additional_len += 1;
+        }
+        size_hint::add_scalar(self.inner.size_hint(), additional_len)
+    }
+}
+
+impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {}
diff --git a/src/free.rs b/src/free.rs
index 2bc72a9..1563679 100644
--- a/src/free.rs
+++ b/src/free.rs
@@ -6,9 +6,6 @@
 #[cfg(feature = "use_std")]
 use std::fmt::Display;
 use std::iter::{self, Zip};
-#[cfg(feature = "use_std")]
-type VecIntoIter<T> = ::std::vec::IntoIter<T>;
-
 #[cfg(feature = "use_std")]
 use Itertools;
 
@@ -214,11 +211,9 @@ pub fn join<I>(iterable: I, sep: &str) -> String
     iterable.into_iter().join(sep)
 }
 
-/// Sort all iterator elements into a new iterator in ascending order.
-///
-/// `IntoIterator` enabled version of [`iterable.sorted()`][1].
+/// Collect all the iterable's elements into a sorted vector in ascending order.
 ///
-/// [1]: trait.Itertools.html#method.sorted
+/// `IntoIterator` enabled version of `iterable.sorted()`.
 ///
 /// ```
 /// use itertools::sorted;
@@ -227,7 +222,7 @@ pub fn join<I>(iterable: I, sep: &str) -> String
 /// assert_equal(sorted("rust".chars()), "rstu".chars());
 /// ```
 #[cfg(feature = "use_std")]
-pub fn sorted<I>(iterable: I) -> VecIntoIter<I::Item>
+pub fn sorted<I>(iterable: I) -> Vec<I::Item>
     where I: IntoIterator,
           I::Item: Ord
 {
diff --git a/src/lib.rs b/src/lib.rs
index 3473c3b..fdedf2b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -40,10 +40,6 @@ use std::fmt;
 use std::hash::Hash;
 #[cfg(feature = "use_std")]
 use std::fmt::Write;
-#[cfg(feature = "use_std")]
-type VecIntoIter<T> = ::std::vec::IntoIter<T>;
-#[cfg(feature = "use_std")]
-use std::iter::FromIterator;
 
 #[macro_use]
 mod impl_macros;
@@ -61,6 +57,7 @@ pub mod structs {
         Product,
         PutBack,
         Batching,
+        Step,
         MapResults,
         Merge,
         MergeBy,
@@ -68,16 +65,16 @@ pub mod structs {
         WhileSome,
         Coalesce,
         TupleCombinations,
+        Flatten,
         Positions,
         Update,
     };
-    #[allow(deprecated)]
-    pub use adaptors::Step;
     #[cfg(feature = "use_std")]
     pub use adaptors::MultiProduct;
     #[cfg(feature = "use_std")]
     pub use combinations::Combinations;
     pub use cons_tuples_impl::ConsTuples;
+    pub use exactly_one_err::ExactlyOneError;
     pub use format::{Format, FormatWith};
     #[cfg(feature = "use_std")]
     pub use groupbylazy::{IntoChunks, Chunk, Chunks, GroupBy, Group, Groups};
@@ -95,7 +92,6 @@ pub mod structs {
     #[cfg(feature = "use_std")]
     pub use rciter_impl::RcIter;
     pub use repeatn::RepeatN;
-    #[allow(deprecated)]
     pub use sources::{RepeatCall, Unfold, Iterate};
     #[cfg(feature = "use_std")]
     pub use tee::Tee;
@@ -107,8 +103,8 @@ pub mod structs {
     pub use zip_longest::ZipLongest;
     pub use ziptuple::Zip;
 }
-#[allow(deprecated)]
 pub use structs::*;
+pub use adaptors::flatten;
 pub use concat_impl::concat;
 pub use cons_tuples_impl::cons_tuples;
 pub use diff::diff_with;
@@ -119,7 +115,6 @@ pub use minmax::MinMaxResult;
 pub use peeking_take_while::PeekingNext;
 pub use process_results_impl::process_results;
 pub use repeatn::repeat_n;
-#[allow(deprecated)]
 pub use sources::{repeat_call, unfold, iterate};
 pub use with_position::Position;
 pub use ziptuple::multizip;
@@ -134,6 +129,7 @@ mod concat_impl;
 mod cons_tuples_impl;
 #[cfg(feature = "use_std")]
 mod combinations;
+mod exactly_one_err;
 mod diff;
 mod format;
 #[cfg(feature = "use_std")]
@@ -216,15 +212,12 @@ macro_rules! iproduct {
 /// returns `None`.
 ///
 /// This is a version of the standard ``.zip()`` that's supporting more than
-/// two iterators. The iterator element type is a tuple with one element
+/// two iterators. The iterator elment type is a tuple with one element
 /// from each of the input iterators. Just like ``.zip()``, the iteration stops
 /// when the shortest of the inputs reaches its end.
 ///
-/// **Note:** The result of this macro is in the general case an iterator
-/// composed of repeated `.zip()` and a `.map()`; it has an anonymous type.
-/// The special cases of one and two arguments produce the equivalent of
-/// `$a.into_iter()` and `$a.into_iter().zip($b)` respectively.
-///
+/// **Note:** The result of this macro is an iterator composed of
+/// repeated `.zip()` and a `.map()`; it has an anonymous type.
 /// Prefer this macro `izip!()` over [`multizip`] for the performance benefits
 /// of using the standard library `.zip()`.
 ///
@@ -266,20 +259,8 @@ macro_rules! izip {
         izip!(@closure ($p, b) => ( $($tup)*, b ) $( , $tail )*)
     };
 
-    // unary
-    ($first:expr $(,)*) => {
-        $crate::__std_iter::IntoIterator::into_iter($first)
-    };
-
-    // binary
-    ($first:expr, $second:expr $(,)*) => {
-        izip!($first)
-            .zip($second)
-    };
-
-    // n-ary where n > 2
     ( $first:expr $( , $rest:expr )* $(,)* ) => {
-        izip!($first)
+        $crate::__std_iter::IntoIterator::into_iter($first)
             $(
                 .zip($rest)
             )*
@@ -632,8 +613,6 @@ pub trait Itertools : Iterator {
     /// let it = (0..8).step(3);
     /// itertools::assert_equal(it, vec![0, 3, 6]);
     /// ```
-    #[deprecated(note="Use std .step_by() instead", since="0.8")]
-    #[allow(deprecated)]
     fn step(self, n: usize) -> Step<Self>
         where Self: Sized
     {
@@ -1112,6 +1091,29 @@ pub trait Itertools : Iterator {
         pad_tail::pad_using(self, min, f)
     }
 
+    /// Flatten an iterator of iterables into a single combined sequence of all
+    /// the elements in the iterables.
+    ///
+    /// This is more or less equivalent to `.flat_map` with an identity
+    /// function.
+    ///
+    /// See also the [`flatten`](fn.flatten.html) function.
+    ///
+    /// ```ignore
+    /// use itertools::Itertools;
+    ///
+    /// let data = vec![vec![1, 2, 3], vec![4, 5, 6]];
+    /// let flattened = data.iter().flatten();
+    ///
+    /// itertools::assert_equal(flattened, &[1, 2, 3, 4, 5, 6]);
+    /// ```
+    fn flatten(self) -> Flatten<Self, <Self::Item as IntoIterator>::IntoIter>
+        where Self: Sized,
+              Self::Item: IntoIterator
+    {
+        adaptors::flatten(self)
+    }
+
     /// Return an iterator adaptor that wraps each element in a `Position` to
     /// ease special-case handling of the first or last elements.
     ///
@@ -1338,12 +1340,11 @@ pub trait Itertools : Iterator {
     ///
     /// itertools::assert_equal(rx.iter(), vec![1, 3, 5, 7, 9]);
     /// ```
-    #[deprecated(note="Use .for_each() instead", since="0.8")]
-    fn foreach<F>(self, f: F)
+    fn foreach<F>(self, mut f: F)
         where F: FnMut(Self::Item),
               Self: Sized,
     {
-        self.for_each(f)
+        self.fold((), move |(), element| f(element))
     }
 
     /// Combine all an iterator's elements into one element by using `Extend`.
@@ -1749,7 +1750,6 @@ pub trait Itertools : Iterator {
     /// The big difference between the computations of `result2` and `result3` is that while
     /// `fold()` called the provided closure for every item of the callee iterator,
     /// `fold_while()` actually stopped iterating as soon as it encountered `Fold::Done(_)`.
-    #[deprecated(note="Use .try_fold() instead", since="0.8")]
     fn fold_while<B, F>(&mut self, init: B, mut f: F) -> FoldWhile<B>
         where Self: Sized,
               F: FnMut(B, Self::Item) -> FoldWhile<B>
@@ -1764,14 +1764,10 @@ pub trait Itertools : Iterator {
         FoldWhile::Continue(acc)
     }
 
-    /// Sort all iterator elements into a new iterator in ascending order.
+    /// Collect all iterator elements into a sorted vector in ascending order.
     ///
     /// **Note:** This consumes the entire iterator, uses the
-    /// `slice::sort()` method and returns the result as a new
-    /// iterator that owns its elements.
-    ///
-    /// The sorted iterator, if directly collected to a `Vec`, is converted
-    /// without any extra copying or allocation cost.
+    /// `slice::sort_by()` method and returns the sorted vector.
     ///
     /// ```
     /// use itertools::Itertools;
@@ -1782,25 +1778,17 @@ pub trait Itertools : Iterator {
     ///                         "abcdef".chars());
     /// ```
     #[cfg(feature = "use_std")]
-    fn sorted(self) -> VecIntoIter<Self::Item>
+    fn sorted(self) -> Vec<Self::Item>
         where Self: Sized,
               Self::Item: Ord
     {
-        // Use .sort() directly since it is not quite identical with
-        // .sort_by(Ord::cmp)
-        let mut v = Vec::from_iter(self);
-        v.sort();
-        v.into_iter()
+        self.sorted_by(Ord::cmp)
     }
 
-    /// Sort all iterator elements into a new iterator in ascending order.
+    /// Collect all iterator elements into a sorted vector.
     ///
     /// **Note:** This consumes the entire iterator, uses the
-    /// `slice::sort_by()` method and returns the result as a new
-    /// iterator that owns its elements.
-    ///
-    /// The sorted iterator, if directly collected to a `Vec`, is converted
-    /// without any extra copying or allocation cost.
+    /// `slice::sort_by()` method and returns the sorted vector.
     ///
     /// ```
     /// use itertools::Itertools;
@@ -1811,29 +1799,27 @@ pub trait Itertools : Iterator {
     /// let oldest_people_first = people
     ///     .into_iter()
     ///     .sorted_by(|a, b| Ord::cmp(&b.1, &a.1))
+    ///     .into_iter()
     ///     .map(|(person, _age)| person);
     ///
     /// itertools::assert_equal(oldest_people_first,
     ///                         vec!["Jill", "Jack", "Jane", "John"]);
     /// ```
     #[cfg(feature = "use_std")]
-    fn sorted_by<F>(self, cmp: F) -> VecIntoIter<Self::Item>
+    fn sorted_by<F>(self, cmp: F) -> Vec<Self::Item>
         where Self: Sized,
               F: FnMut(&Self::Item, &Self::Item) -> Ordering,
     {
-        let mut v = Vec::from_iter(self);
+        let mut v: Vec<Self::Item> = self.collect();
+
         v.sort_by(cmp);
-        v.into_iter()
+        v
     }
 
-    /// Sort all iterator elements into a new iterator in ascending order.
+    /// Collect all iterator elements into a sorted vector.
     ///
     /// **Note:** This consumes the entire iterator, uses the
-    /// `slice::sort_by_key()` method and returns the result as a new
-    /// iterator that owns its elements.
-    ///
-    /// The sorted iterator, if directly collected to a `Vec`, is converted
-    /// without any extra copying or allocation cost.
+    /// `slice::sort_by_key()` method and returns the sorted vector.
     ///
     /// ```
     /// use itertools::Itertools;
@@ -1844,20 +1830,22 @@ pub trait Itertools : Iterator {
     /// let oldest_people_first = people
     ///     .into_iter()
     ///     .sorted_by_key(|x| -x.1)
+    ///     .into_iter()
     ///     .map(|(person, _age)| person);
     ///
     /// itertools::assert_equal(oldest_people_first,
     ///                         vec!["Jill", "Jack", "Jane", "John"]);
     /// ```
     #[cfg(feature = "use_std")]
-    fn sorted_by_key<K, F>(self, f: F) -> VecIntoIter<Self::Item>
+    fn sorted_by_key<K, F>(self, f: F) -> Vec<Self::Item>
         where Self: Sized,
               K: Ord,
               F: FnMut(&Self::Item) -> K,
     {
-        let mut v = Vec::from_iter(self);
+        let mut v: Vec<Self::Item> = self.collect();
+
         v.sort_by_key(f);
-        v.into_iter()
+        v
     }
 
     /// Collect all iterator elements into one of two
@@ -1902,13 +1890,13 @@ pub trait Itertools : Iterator {
 
     /// Return a `HashMap` of keys mapped to `Vec`s of values. Keys and values
     /// are taken from `(Key, Value)` tuple pairs yielded by the input iterator.
-    /// 
+    ///
     /// ```
     /// use itertools::Itertools;
-    /// 
+    ///
     /// let data = vec![(0, 10), (2, 12), (3, 13), (0, 20), (3, 33), (2, 42)];
     /// let lookup = data.into_iter().into_group_map();
-    /// 
+    ///
     /// assert_eq!(lookup[&0], vec![10, 20]);
     /// assert_eq!(lookup.get(&1), None);
     /// assert_eq!(lookup[&2], vec![12, 42]);
@@ -1997,6 +1985,42 @@ pub trait Itertools : Iterator {
             |x, y, _, _| Ordering::Less == compare(x, y)
         )
     }
+
+    /// If the iterator yields exactly one element, that element will be returned, otherwise
+    /// an error will be returned containing an iterator that has the same output as the input
+    /// iterator.
+    ///
+    /// This provides an additional layer of validation over just calling `Iterator::next()`.
+    /// If your assumption that there should only be one element yielded is false this provides
+    /// the opportunity to detect and handle that, preventing errors at a distance.
+    ///
+    /// # Examples
+    /// ```
+    /// use itertools::Itertools;
+    ///
+    /// assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2);
+    /// assert!((0..10).filter(|&x| x > 1 && x < 4).exactly_one().unwrap_err().eq(2..4));
+    /// assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5));
+    /// assert!((0..10).filter(|&x| false).exactly_one().unwrap_err().eq(0..0));
+    /// ```
+    fn exactly_one(mut self) -> Result<Self::Item, ExactlyOneError<Self>>
+    where
+        Self: Sized,
+    {
+        match self.next() {
+            Some(first) => {
+                match self.next() {
+                    Some(second) => {
+                        Err(ExactlyOneError::new((Some(first), Some(second)), self))
+                    }
+                    None => {
+                        Ok(first)
+                    }
+                }
+            }
+            None => Err(ExactlyOneError::new((None, None), self)),
+        }
+    }
 }
 
 impl<T: ?Sized> Itertools for T where T: Iterator { }
diff --git a/src/sources.rs b/src/sources.rs
index a579f3d..562801b 100644
--- a/src/sources.rs
+++ b/src/sources.rs
@@ -1,12 +1,10 @@
 //! Iterators that are sources (produce elements from parameters,
 //! not from another iterator).
-#![allow(deprecated)]
 
 use std::fmt;
 use std::mem;
 
 /// See [`repeat_call`](../fn.repeat_call.html) for more information.
-#[deprecated(note="Use std repeat_with() instead", since="0.8")]
 pub struct RepeatCall<F> {
     f: F,
 }
@@ -38,7 +36,6 @@ impl<F> fmt::Debug for RepeatCall<F>
 ///     vec![1, 1, 1, 1, 1]
 /// );
 /// ```
-#[deprecated(note="Use std repeat_with() instead", since="0.8")]
 pub fn repeat_call<F, A>(function: F) -> RepeatCall<F>
     where F: FnMut() -> A
 {


Test patch:
diff --git a/tests/quick.rs b/tests/quick.rs
index e0c61b4..6859758 100644
--- a/tests/quick.rs
+++ b/tests/quick.rs
@@ -6,7 +6,6 @@
 #[macro_use] extern crate itertools;
 
 extern crate quickcheck;
-extern crate rand;
 
 use std::default::Default;
 
@@ -18,6 +17,7 @@ use itertools::{
     multizip,
     EitherOrBoth,
 };
+use itertools::flatten;
 use itertools::free::{
     cloned,
     enumerate,
@@ -29,8 +29,6 @@ use itertools::free::{
     zip_eq,
 };
 
-use rand::Rng;
-use rand::seq::SliceRandom;
 use quickcheck::TestResult;
 
 /// Trait for size hint modifier types
@@ -80,8 +78,8 @@ impl qc::Arbitrary for Inexact {
         let ue_choices = &[0, ue_value, usize::max_value()];
         let oe_choices = &[0, oe_value, usize::max_value()];
         Inexact {
-            underestimate: *ue_choices.choose(g).unwrap(),
-            overestimate: *oe_choices.choose(g).unwrap(),
+            underestimate: *g.choose(ue_choices).unwrap(),
+            overestimate: *g.choose(oe_choices).unwrap(),
         }
     }
 
@@ -405,7 +403,6 @@ quickcheck! {
         assert_eq!(answer.into_iter().last(), a.clone().multi_cartesian_product().last());
     }
 
-    #[allow(deprecated)]
     fn size_step(a: Iter<i16, Exact>, s: usize) -> bool {
         let mut s = s;
         if s == 0 {
@@ -415,8 +412,6 @@ quickcheck! {
         correct_size_hint(filt.step(s)) &&
             exact_size(a.step(s))
     }
-
-    #[allow(deprecated)]
     fn equal_step(a: Iter<i16>, s: usize) -> bool {
         let mut s = s;
         if s == 0 {
@@ -429,8 +424,6 @@ quickcheck! {
             keep
         }))
     }
-
-    #[allow(deprecated)]
     fn equal_step_vec(a: Vec<i16>, s: usize) -> bool {
         let mut s = s;
         if s == 0 {
@@ -611,6 +604,16 @@ quickcheck! {
         true
     }
 
+    fn equal_flatten(a: Vec<Option<i32>>) -> bool {
+        itertools::equal(flatten(&a),
+                         a.iter().filter_map(|x| x.as_ref()))
+    }
+
+    fn equal_flatten_vec(a: Vec<Vec<u8>>) -> bool {
+        itertools::equal(flatten(&a),
+                         a.iter().flat_map(|x| x))
+    }
+
     fn equal_combinations_2(a: Vec<u8>) -> bool {
         let mut v = Vec::new();
         for (i, x) in enumerate(&a) {
@@ -985,7 +988,6 @@ quickcheck! {
 }
 
 quickcheck! {
-    #[allow(deprecated)]
     fn tree_fold1_f64(mut a: Vec<f64>) -> TestResult {
         fn collapse_adjacent<F>(x: Vec<f64>, mut f: F) -> Vec<f64>
             where F: FnMut(f64, f64) -> f64
diff --git a/tests/test_core.rs b/tests/test_core.rs
index cf97abd..e215255 100644
--- a/tests/test_core.rs
+++ b/tests/test_core.rs
@@ -7,8 +7,7 @@
 
 #[macro_use] extern crate itertools as it;
 
-use core::iter;
-
+use it::flatten;
 use it::Itertools;
 use it::interleave;
 use it::multizip;
@@ -55,23 +54,8 @@ fn izip_macro() {
     assert!(zip.next().is_none());
 }
 
-#[test]
-fn izip2() {
-    let _zip1: iter::Zip<_, _> = izip!(1.., 2..);
-    let _zip2: iter::Zip<_, _> = izip!(1.., 2.., );
-}
-
 #[test]
 fn izip3() {
-    let mut zip: iter::Map<iter::Zip<_, _>, _> = izip!(0..3, 0..2, 0..2i8);
-    for i in 0..2 {
-        assert!((i as usize, i, i as i8) == zip.next().unwrap());
-    }
-    assert!(zip.next().is_none());
-}
-
-#[test]
-fn multizip3() {
     let mut zip = multizip((0..3, 0..2, 0..2i8));
     for i in 0..2 {
         assert!((i as usize, i, i as i8) == zip.next().unwrap());
@@ -113,7 +97,6 @@ fn test_interleave() {
     it::assert_equal(it, rs.iter());
 }
 
-#[allow(deprecated)]
 #[test]
 fn foreach() {
     let xs = [1i32, 2, 3];
@@ -160,7 +143,6 @@ fn test_put_back() {
     it::assert_equal(pb, xs.iter().cloned());
 }
 
-#[allow(deprecated)]
 #[test]
 fn step() {
     it::assert_equal((0..10).step(1), 0..10);
@@ -168,7 +150,6 @@ fn step() {
     it::assert_equal((0..10).step(10), 0..1);
 }
 
-#[allow(deprecated)]
 #[test]
 fn merge() {
     it::assert_equal((0..10).step(2).merge((1..10).step(2)), 0..10);
@@ -238,6 +219,19 @@ fn part() {
     assert_eq!(data, [9, 6, 3, 4, 5, 2, 7, 8, 1]);
 }
 
+#[test]
+fn flatten_clone() {
+    let data = &[
+        &[1,2,3],
+        &[4,5,6]
+    ];
+    let flattened1 = flatten(data.into_iter().cloned());
+    let flattened2 = flattened1.clone();
+
+    it::assert_equal(flattened1, &[1,2,3,4,5,6]);
+    it::assert_equal(flattened2, &[1,2,3,4,5,6]);
+}
+
 #[test]
 fn tree_fold1() {
     for i in 0..100 {
diff --git a/tests/test_std.rs b/tests/test_std.rs
index b587f44..35e0529 100644
--- a/tests/test_std.rs
+++ b/tests/test_std.rs
@@ -2,6 +2,7 @@
 #[macro_use] extern crate itertools as it;
 extern crate permutohedron;
 
+use it::flatten;
 use it::Itertools;
 use it::multizip;
 use it::multipeek;
@@ -165,7 +166,6 @@ fn test_rciter() {
     assert_eq!(z.next(), Some((0, 1)));
 }
 
-#[allow(deprecated)]
 #[test]
 fn trait_pointers() {
     struct ByRef<'r, I: ?Sized>(&'r mut I) where I: 'r;
@@ -221,7 +221,6 @@ fn merge_by_btree() {
     it::assert_equal(results, expected.into_iter());
 }
 
-#[allow(deprecated)]
 #[test]
 fn kmerge() {
     let its = (0..4).map(|s| (s..10).step(4));
@@ -229,7 +228,6 @@ fn kmerge() {
     it::assert_equal(its.kmerge(), 0..10);
 }
 
-#[allow(deprecated)]
 #[test]
 fn kmerge_2() {
     let its = vec![3, 2, 1, 0].into_iter().map(|s| (s..10).step(4));
@@ -271,19 +269,19 @@ fn sorted_by() {
     let sc = [3, 4, 1, 2].iter().cloned().sorted_by(|&a, &b| {
         a.cmp(&b)
     });
-    it::assert_equal(sc, vec![1, 2, 3, 4]);
+    assert_eq!(sc, vec![1, 2, 3, 4]);
 
     let v = (0..5).sorted_by(|&a, &b| a.cmp(&b).reverse());
-    it::assert_equal(v, vec![4, 3, 2, 1, 0]);
+    assert_eq!(v, vec![4, 3, 2, 1, 0]);
 }
 
 #[test]
 fn sorted_by_key() {
     let sc = [3, 4, 1, 2].iter().cloned().sorted_by_key(|&x| x);
-    it::assert_equal(sc, vec![1, 2, 3, 4]);
+    assert_eq!(sc, vec![1, 2, 3, 4]);
 
     let v = (0..5).sorted_by_key(|&x| -x);
-    it::assert_equal(v, vec![4, 3, 2, 1, 0]);
+    assert_eq!(v, vec![4, 3, 2, 1, 0]);
 }
 
 #[test]
@@ -540,6 +538,23 @@ fn concat_non_empty() {
     assert_eq!(data.into_iter().concat(), vec![1,2,3,4,5,6,7,8,9])
 }
 
+#[test]
+fn flatten_iter() {
+    let data = vec![vec![1,2,3], vec![4,5], vec![], vec![6]];
+    it::assert_equal(flatten(data), vec![1,2,3,4,5,6]);
+}
+
+#[test]
+fn flatten_fold() {
+    let xs = [0, 1, 1, 1, 2, 1, 3, 3];
+    let ch = xs.iter().chunks(3);
+    let mut iter = flatten(&ch);
+    iter.next();
+    let mut xs_d = Vec::new();
+    iter.fold((), |(), &elt| xs_d.push(elt));
+    assert_eq!(&xs_d[..], &xs[1..]);
+}
+
 #[test]
 fn combinations() {
     assert!((1..3).combinations(5).next().is_none());
@@ -687,7 +702,6 @@ fn while_some() {
     it::assert_equal(ns, vec![1, 2, 3, 4]);
 }
 
-#[allow(deprecated)]
 #[test]
 fn fold_while() {
     let mut iterations = 0;