From b58c106483ba1e570411044f34ec04358b455455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Fri, 5 Jun 2020 15:59:35 +0200 Subject: [PATCH 01/12] Added Range iterator --- src/lib.rs | 271 +++++++++++++++++++++++++++++---------------------- src/range.rs | 82 ++++++++++++++++ 2 files changed, 234 insertions(+), 119 deletions(-) create mode 100644 src/range.rs diff --git a/src/lib.rs b/src/lib.rs index 7a7abb2a8..2694dbb55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,7 @@ //! use itertools::interleave; //! //! for elt in interleave(&[1, 2, 3], &[2, 3, 4]) { -//! /* loop body */ +//! /* loop body */ //! } //! ``` //! @@ -37,8 +37,8 @@ //! - `use_std` //! - Enabled by default. //! - Disable to compile itertools using `#![no_std]`. This disables -//! any items that depend on collections (like `group_by`, `unique`, -//! `kmerge`, `join` and many more). +//! any items that depend on collections (like `group_by`, `unique`, +//! `kmerge`, `join` and many more). //! //! ## Rust Version //! @@ -138,6 +138,7 @@ pub mod structs { pub use crate::zip_eq_impl::ZipEq; pub use crate::zip_longest::ZipLongest; pub use crate::ziptuple::Zip; + pub use crate::range::Range; } /// Traits helpful for using certain `Itertools` methods in generic contexts. @@ -161,6 +162,7 @@ pub use crate::repeatn::repeat_n; pub use crate::sources::{repeat_call, unfold, iterate}; pub use crate::with_position::Position; pub use crate::ziptuple::multizip; +pub use crate::range::range; mod adaptors; mod either_or_both; pub use crate::either_or_both::EitherOrBoth; @@ -213,6 +215,7 @@ mod with_position; mod zip_eq_impl; mod zip_longest; mod ziptuple; +mod range; #[macro_export] /// Create an iterator over the “cartesian product” of iterators. @@ -280,7 +283,7 @@ macro_rules! iproduct { /// let inputs = [3, 7, 9, 6]; /// /// for (r, index, input) in izip!(&mut results, 0..10, &inputs) { -/// *r = index * 10 + input; +/// *r = index * 10 + input; /// } /// /// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]); @@ -443,6 +446,36 @@ pub trait Itertools : Iterator { zip_eq(self, other) } + /// Limits an iterator to a given range. + /// Similar to [`Iterator::skip`] and [`Iterator::take`], + /// but some may consider it to be more readable. + /// + /// ``` + /// use itertools::Itertools; + /// + /// let vec = vec![3, 1, 4, 1, 5]; + /// + /// let mut range: Vec<_> = + /// vec.iter().range(1..=3).copied().collect(); + /// assert_eq!(&range, &[1, 4, 1]); + /// + /// // It works with other types of ranges, too + /// range = vec.iter().range(..2).copied().collect(); + /// assert_eq!(&range, &[3, 1]); + /// + /// range = vec.iter().range(2..).copied().collect(); + /// assert_eq!(&range, &[4, 1, 5]); + /// + /// range = vec.iter().range(..).copied().collect(); + /// assert_eq!(range, vec); + /// ``` + fn range(self, r: R) -> Range + where R: core::ops::RangeBounds, + Self: Sized + { + range::range(self, r) + } + /// A “meta iterator adaptor”. Its closure receives a reference to the /// iterator and may pick off as many elements as it likes, to produce the /// next iterator element. @@ -454,14 +487,14 @@ pub trait Itertools : Iterator { /// /// // An adaptor that gathers elements in pairs /// let pit = (0..4).batching(|it| { - /// match it.next() { - /// None => None, - /// Some(x) => match it.next() { - /// None => None, - /// Some(y) => Some((x, y)), - /// } - /// } - /// }); + /// match it.next() { + /// None => None, + /// Some(x) => match it.next() { + /// None => None, + /// Some(y) => Some((x, y)), + /// } + /// } + /// }); /// /// itertools::assert_equal(pit, vec![(0, 1), (2, 3)]); /// ``` @@ -497,13 +530,13 @@ pub trait Itertools : Iterator { /// /// // group data into runs of larger than zero or not. /// let data = vec![1, 3, -2, -2, 1, 0, 1, 2]; - /// // groups: |---->|------>|--------->| + /// // groups: |---->|------>|--------->| /// /// // Note: The `&` is significant here, `GroupBy` is iterable /// // only by reference. You can also call `.into_iter()` explicitly. /// let mut data_grouped = Vec::new(); /// for (key, group) in &data.into_iter().group_by(|elt| *elt >= 0) { - /// data_grouped.push((key, group.collect())); + /// data_grouped.push((key, group.collect())); /// } /// assert_eq!(data_grouped, vec![(true, vec![1, 3]), (false, vec![-2, -2]), (true, vec![1, 0, 1, 2])]); /// ``` @@ -539,8 +572,8 @@ pub trait Itertools : Iterator { /// // Note: The `&` is significant here, `IntoChunks` is iterable /// // only by reference. You can also call `.into_iter()` explicitly. /// for chunk in &data.into_iter().chunks(3) { - /// // Check that the sum of each chunk is 4. - /// assert_eq!(4, chunk.sum()); + /// // Check that the sum of each chunk is 4. + /// assert_eq!(4, chunk.sum()); /// } /// ``` #[cfg(feature = "use_std")] @@ -562,7 +595,7 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// let mut v = Vec::new(); /// for (a, b) in (1..5).tuple_windows() { - /// v.push((a, b)); + /// v.push((a, b)); /// } /// assert_eq!(v, vec![(1, 2), (2, 3), (3, 4)]); /// @@ -602,7 +635,7 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// let mut v = Vec::new(); /// for (a, b) in (1..5).circular_tuple_windows() { - /// v.push((a, b)); + /// v.push((a, b)); /// } /// assert_eq!(v, vec![(1, 2), (2, 3), (3, 4), (4, 1)]); /// @@ -633,7 +666,7 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// let mut v = Vec::new(); /// for (a, b) in (1..5).tuples() { - /// v.push((a, b)); + /// v.push((a, b)); /// } /// assert_eq!(v, vec![(1, 2), (3, 4)]); /// @@ -801,7 +834,7 @@ pub trait Itertools : Iterator { /// and remove `i` from its source iterator /// - Emit `EitherOrBoth::Right(j)` when `i > j`, /// and remove `j` from its source iterator - /// - Emit `EitherOrBoth::Both(i, j)` when `i == j`, + /// - Emit `EitherOrBoth::Both(i, j)` when `i == j`, /// and remove both `i` and `j` from their respective source iterators /// /// ``` @@ -811,11 +844,11 @@ pub trait Itertools : Iterator { /// let ki = (0..10).step(3); /// let ku = (0..10).step(5); /// let ki_ku = ki.merge_join_by(ku, |i, j| i.cmp(j)).map(|either| { - /// match either { - /// Left(_) => "Ki", - /// Right(_) => "Ku", - /// Both(_, _) => "KiKu" - /// } + /// match either { + /// Left(_) => "Ki", + /// Right(_) => "Ku", + /// Both(_, _) => "KiKu" + /// } /// }); /// /// itertools::assert_equal(ki_ku, vec!["KiKu", "Ki", "Ku", "Ki", "Ki"]); @@ -919,7 +952,7 @@ pub trait Itertools : Iterator { /// ``` /// use itertools::Itertools; /// let mut multi_prod = (0..3).map(|i| (i * 2)..(i * 2 + 2)) - /// .multi_cartesian_product(); + /// .multi_cartesian_product(); /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 4])); /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 5])); /// assert_eq!(multi_prod.next(), Some(vec![0, 3, 4])); @@ -961,12 +994,12 @@ pub trait Itertools : Iterator { /// // sum same-sign runs together /// let data = vec![-1., -2., -3., 3., 1., 0., -1.]; /// itertools::assert_equal(data.into_iter().coalesce(|x, y| - /// if (x >= 0.) == (y >= 0.) { - /// Ok(x + y) - /// } else { - /// Err((x, y)) - /// }), - /// vec![-6., 4., -1.]); + /// if (x >= 0.) == (y >= 0.) { + /// Ok(x + y) + /// } else { + /// Err((x, y)) + /// }), + /// vec![-6., 4., -1.]); /// ``` fn coalesce(self, f: F) -> Coalesce where Self: Sized, @@ -988,7 +1021,7 @@ pub trait Itertools : Iterator { /// /// let data = vec![1., 1., 2., 3., 3., 2., 2.]; /// itertools::assert_equal(data.into_iter().dedup(), - /// vec![1., 2., 3., 2.]); + /// vec![1., 2., 3., 2.]); /// ``` fn dedup(self) -> Dedup where Self: Sized, @@ -1010,7 +1043,7 @@ pub trait Itertools : Iterator { /// /// let data = vec![(0, 1.), (1, 1.), (0, 2.), (0, 3.), (1, 3.), (1, 2.), (2, 2.)]; /// itertools::assert_equal(data.into_iter().dedup_by(|x, y| x.1 == y.1), - /// vec![(0, 1.), (0, 2.), (0, 3.), (1, 2.)]); + /// vec![(0, 1.), (0, 2.), (0, 3.), (1, 2.)]); /// ``` fn dedup_by(self, cmp: Cmp) -> DedupBy where Self: Sized, @@ -1032,7 +1065,7 @@ pub trait Itertools : Iterator { /// /// let data = vec![1., 1., 2., 3., 3., 2., 2.]; /// itertools::assert_equal(data.into_iter().dedup_with_count(), - /// vec![(2, 1.), (1, 2.), (2, 3.), (2, 2.)]); + /// vec![(2, 1.), (1, 2.), (2, 3.), (2, 2.)]); /// ``` fn dedup_with_count(self) -> DedupWithCount where Self: Sized, @@ -1054,7 +1087,7 @@ pub trait Itertools : Iterator { /// /// let data = vec![(0, 1.), (1, 1.), (0, 2.), (0, 3.), (1, 3.), (1, 2.), (2, 2.)]; /// itertools::assert_equal(data.into_iter().dedup_by_with_count(|x, y| x.1 == y.1), - /// vec![(2, (0, 1.)), (1, (0, 2.)), (2, (0, 3.)), (2, (1, 2.))]); + /// vec![(2, (0, 1.)), (1, (0, 2.)), (2, (0, 3.)), (2, (1, 2.))]); /// ``` fn dedup_by_with_count(self, cmp: Cmp) -> DedupByWithCount where Self: Sized, @@ -1079,7 +1112,7 @@ pub trait Itertools : Iterator { /// /// let data = vec![10, 20, 30, 20, 40, 10, 50]; /// itertools::assert_equal(data.into_iter().unique(), - /// vec![10, 20, 30, 40, 50]); + /// vec![10, 20, 30, 40, 50]); /// ``` #[cfg(feature = "use_std")] fn unique(self) -> Unique @@ -1105,7 +1138,7 @@ pub trait Itertools : Iterator { /// /// let data = vec!["a", "bb", "aa", "c", "ccc"]; /// itertools::assert_equal(data.into_iter().unique_by(|s| s.len()), - /// vec!["a", "bb", "ccc"]); + /// vec!["a", "bb", "ccc"]); /// ``` #[cfg(feature = "use_std")] fn unique_by(self, f: F) -> UniqueBy @@ -1148,7 +1181,7 @@ pub trait Itertools : Iterator { /// let mut hexadecimals = "0123456789abcdef".chars(); /// /// let decimals = hexadecimals.take_while_ref(|c| c.is_numeric()) - /// .collect::(); + /// .collect::(); /// assert_eq!(decimals, "0123456789"); /// assert_eq!(hexadecimals.next(), Some('a')); /// @@ -1170,8 +1203,8 @@ pub trait Itertools : Iterator { /// /// // List all hexadecimal digits /// itertools::assert_equal( - /// (0..).map(|i| std::char::from_digit(i, 16)).while_some(), - /// "0123456789abcdef".chars()); + /// (0..).map(|i| std::char::from_digit(i, 16)).while_some(), + /// "0123456789abcdef".chars()); /// /// ``` fn while_some(self) -> WhileSome @@ -1191,7 +1224,7 @@ pub trait Itertools : Iterator { /// /// let mut v = Vec::new(); /// for (a, b) in (1..5).tuple_combinations() { - /// v.push((a, b)); + /// v.push((a, b)); /// } /// assert_eq!(v, vec![(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]); /// @@ -1232,10 +1265,10 @@ pub trait Itertools : Iterator { /// /// let it = (1..5).combinations(3); /// itertools::assert_equal(it, vec![ - /// vec![1, 2, 3], - /// vec![1, 2, 4], - /// vec![1, 3, 4], - /// vec![2, 3, 4], + /// vec![1, 2, 3], + /// vec![1, 2, 4], + /// vec![1, 3, 4], + /// vec![2, 3, 4], /// ]); /// ``` /// @@ -1245,9 +1278,9 @@ pub trait Itertools : Iterator { /// /// let it = vec![1, 2, 2].into_iter().combinations(2); /// itertools::assert_equal(it, vec![ - /// vec![1, 2], // Note: these are the same - /// vec![1, 2], // Note: these are the same - /// vec![2, 2], + /// vec![1, 2], // Note: these are the same + /// vec![1, 2], // Note: these are the same + /// vec![2, 2], /// ]); /// ``` #[cfg(feature = "use_std")] @@ -1269,12 +1302,12 @@ pub trait Itertools : Iterator { /// /// let it = (1..4).combinations_with_replacement(2); /// itertools::assert_equal(it, vec![ - /// vec![1, 1], - /// vec![1, 2], - /// vec![1, 3], - /// vec![2, 2], - /// vec![2, 3], - /// vec![3, 3], + /// vec![1, 1], + /// vec![1, 2], + /// vec![1, 3], + /// vec![2, 2], + /// vec![2, 3], + /// vec![3, 3], /// ]); /// ``` #[cfg(feature = "use_std")] @@ -1300,12 +1333,12 @@ pub trait Itertools : Iterator { /// /// let perms = (5..8).permutations(2); /// itertools::assert_equal(perms, vec![ - /// vec![5, 6], - /// vec![5, 7], - /// vec![6, 5], - /// vec![6, 7], - /// vec![7, 5], - /// vec![7, 6], + /// vec![5, 6], + /// vec![5, 7], + /// vec![6, 5], + /// vec![6, 7], + /// vec![7, 5], + /// vec![7, 6], /// ]); /// ``` /// @@ -1316,8 +1349,8 @@ pub trait Itertools : Iterator { /// /// let it = vec![2, 2].into_iter().permutations(2); /// itertools::assert_equal(it, vec![ - /// vec![2, 2], // Note: these are the same - /// vec![2, 2], // Note: these are the same + /// vec![2, 2], // Note: these are the same + /// vec![2, 2], // Note: these are the same /// ]); /// ``` /// @@ -1366,10 +1399,10 @@ pub trait Itertools : Iterator { /// /// let it = (0..4).with_position(); /// itertools::assert_equal(it, - /// vec![Position::First(0), - /// Position::Middle(1), - /// Position::Middle(2), - /// Position::Last(3)]); + /// vec![Position::First(0), + /// Position::Middle(1), + /// Position::Middle(2), + /// Position::Last(3)]); /// /// let it = (0..1).with_position(); /// itertools::assert_equal(it, vec![Position::Only(0)]); @@ -1451,9 +1484,9 @@ pub trait Itertools : Iterator { /// let iter = 1..3; /// /// if let Some((x, y)) = iter.collect_tuple() { - /// assert_eq!((x, y), (1, 2)) + /// assert_eq!((x, y), (1, 2)) /// } else { - /// panic!("Expected two elements") + /// panic!("Expected two elements") /// } /// ``` fn collect_tuple(mut self) -> Option @@ -1604,7 +1637,7 @@ pub trait Itertools : Iterator { /// /// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]]; /// assert_eq!(input.into_iter().concat(), - /// vec![1, 2, 3, 4, 5, 6]); + /// vec![1, 2, 3, 4, 5, 6]); /// ``` fn concat(self) -> Self::Item where Self: Sized, @@ -1632,14 +1665,14 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// /// fn process_dir_entries(entries: &[fs::DirEntry]) { - /// // ... + /// // ... /// } /// /// fn do_stuff() -> std::io::Result<()> { - /// let entries: Vec<_> = fs::read_dir(".")?.try_collect()?; - /// process_dir_entries(&entries); + /// let entries: Vec<_> = fs::read_dir(".")?.try_collect()?; + /// process_dir_entries(&entries); /// - /// Ok(()) + /// Ok(()) /// } /// ``` #[cfg(feature = "use_std")] @@ -1724,8 +1757,8 @@ pub trait Itertools : Iterator { /// /// let data = [1.1, 2.71828, -3.]; /// assert_eq!( - /// format!("{:.2}", data.iter().format(", ")), - /// "1.10, 2.72, -3.00"); + /// format!("{:.2}", data.iter().format(", ")), + /// "1.10, 2.72, -3.00"); /// ``` fn format(self, sep: &str) -> Format where Self: Sized, @@ -1752,16 +1785,16 @@ pub trait Itertools : Iterator { /// let data = [1.1, 2.71828, -3.]; /// let data_formatter = data.iter().format_with(", ", |elt, f| f(&format_args!("{:.2}", elt))); /// assert_eq!(format!("{}", data_formatter), - /// "1.10, 2.72, -3.00"); + /// "1.10, 2.72, -3.00"); /// /// // .format_with() is recursively composable /// let matrix = [[1., 2., 3.], - /// [4., 5., 6.]]; + /// [4., 5., 6.]]; /// let matrix_formatter = matrix.iter().format_with("\n", |row, f| { - /// f(&row.iter().format_with(", ", |elt, g| g(&elt))) - /// }); + /// f(&row.iter().format_with(", ", |elt, g| g(&elt))) + /// }); /// assert_eq!(format!("{}", matrix_formatter), - /// "1, 2, 3\n4, 5, 6"); + /// "1, 2, 3\n4, 5, 6"); /// /// /// ``` @@ -1802,16 +1835,16 @@ pub trait Itertools : Iterator { /// /// let values = [1, 2, -2, -1, 2, 1]; /// assert_eq!( - /// values.iter() - /// .map(Ok::<_, ()>) - /// .fold_results(0, Add::add), - /// Ok(3) + /// values.iter() + /// .map(Ok::<_, ()>) + /// .fold_results(0, Add::add), + /// Ok(3) /// ); /// assert!( - /// values.iter() - /// .map(|&x| if x >= 0 { Ok(x) } else { Err("Negative number") }) - /// .fold_results(0, Add::add) - /// .is_err() + /// values.iter() + /// .map(|&x| if x >= 0 { Ok(x) } else { Err("Negative number") }) + /// .fold_results(0, Add::add) + /// .is_err() /// ); /// ``` fn fold_results(&mut self, mut start: B, mut f: F) -> Result @@ -1893,8 +1926,8 @@ pub trait Itertools : Iterator { /// └─f └─f └─f │ /// │ │ │ │ /// └───f └─f - /// │ │ - /// └─────f + /// │ │ + /// └─────f /// ``` /// /// Which, for non-associative functions, will typically produce a different @@ -1914,17 +1947,17 @@ pub trait Itertools : Iterator { /// // The same tree as above /// let num_strings = (1..8).map(|x| x.to_string()); /// assert_eq!(num_strings.tree_fold1(|x, y| format!("f({}, {})", x, y)), - /// Some(String::from("f(f(f(1, 2), f(3, 4)), f(f(5, 6), 7))"))); + /// Some(String::from("f(f(f(1, 2), f(3, 4)), f(f(5, 6), 7))"))); /// /// // Like fold1, an empty iterator produces None /// assert_eq!((0..0).tree_fold1(|x, y| x * y), None); /// /// // tree_fold1 matches fold1 for associative operations... /// assert_eq!((0..10).tree_fold1(|x, y| x + y), - /// (0..10).fold1(|x, y| x + y)); + /// (0..10).fold1(|x, y| x + y)); /// // ...but not for non-associative ones /// assert_ne!((0..10).tree_fold1(|x, y| x - y), - /// (0..10).fold1(|x, y| x - y)); + /// (0..10).fold1(|x, y| x - y)); /// ``` fn tree_fold1(mut self, mut f: F) -> Option where F: FnMut(Self::Item, Self::Item) -> Self::Item, @@ -1969,7 +2002,7 @@ pub trait Itertools : Iterator { Ok(y) => x = f(x, y), // If we ran out of items, combine whatever we did manage - // to get. It's better combined with the current value + // to get. It's better combined with the current value // than something in a parent frame, because the tree in // the parent is always as least as big as this one. Err(None) => return Err(Some(x)), @@ -2000,20 +2033,20 @@ pub trait Itertools : Iterator { /// /// // for loop: /// for i in &numbers { - /// if *i > 5 { - /// break; - /// } - /// result = result + i; + /// if *i > 5 { + /// break; + /// } + /// result = result + i; /// } /// /// // fold: /// let result2 = numbers.iter().fold(0, |acc, x| { - /// if *x > 5 { acc } else { acc + x } + /// if *x > 5 { acc } else { acc + x } /// }); /// /// // fold_while: /// let result3 = numbers.iter().fold_while(0, |acc, x| { - /// if *x > 5 { Done(acc) } else { Continue(acc + x) } + /// if *x > 5 { Done(acc) } else { Continue(acc + x) } /// }).into_inner(); /// /// // they're the same @@ -2112,7 +2145,7 @@ pub trait Itertools : Iterator { /// // sort the letters of the text in ascending order /// let text = "bdacfe"; /// itertools::assert_equal(text.chars().sorted(), - /// "abcdef".chars()); + /// "abcdef".chars()); /// ``` #[cfg(feature = "use_std")] fn sorted(self) -> VecIntoIter @@ -2142,12 +2175,12 @@ pub trait Itertools : Iterator { /// let people = vec![("Jane", 20), ("John", 18), ("Jill", 30), ("Jack", 27)]; /// /// let oldest_people_first = people - /// .into_iter() - /// .sorted_by(|a, b| Ord::cmp(&b.1, &a.1)) - /// .map(|(person, _age)| person); + /// .into_iter() + /// .sorted_by(|a, b| Ord::cmp(&b.1, &a.1)) + /// .map(|(person, _age)| person); /// /// itertools::assert_equal(oldest_people_first, - /// vec!["Jill", "Jack", "Jane", "John"]); + /// vec!["Jill", "Jack", "Jane", "John"]); /// ``` #[cfg(feature = "use_std")] fn sorted_by(self, cmp: F) -> VecIntoIter @@ -2175,12 +2208,12 @@ pub trait Itertools : Iterator { /// let people = vec![("Jane", 20), ("John", 18), ("Jill", 30), ("Jack", 27)]; /// /// let oldest_people_first = people - /// .into_iter() - /// .sorted_by_key(|x| -x.1) - /// .map(|(person, _age)| person); + /// .into_iter() + /// .sorted_by_key(|x| -x.1) + /// .map(|(person, _age)| person); /// /// itertools::assert_equal(oldest_people_first, - /// vec!["Jill", "Jack", "Jane", "John"]); + /// vec!["Jill", "Jack", "Jane", "John"]); /// ``` #[cfg(feature = "use_std")] fn sorted_by_key(self, f: F) -> VecIntoIter @@ -2203,13 +2236,13 @@ pub trait Itertools : Iterator { /// let successes_and_failures = vec![Ok(1), Err(false), Err(true), Ok(2)]; /// /// let (successes, failures): (Vec<_>, Vec<_>) = successes_and_failures - /// .into_iter() - /// .partition_map(|r| { - /// match r { - /// Ok(v) => Either::Left(v), - /// Err(v) => Either::Right(v), - /// } - /// }); + /// .into_iter() + /// .partition_map(|r| { + /// match r { + /// Ok(v) => Either::Left(v), + /// Err(v) => Either::Right(v), + /// } + /// }); /// /// assert_eq!(successes, [1, 2]); /// assert_eq!(failures, [false, true]); @@ -2300,7 +2333,7 @@ pub trait Itertools : Iterator { /// The return value is a variant of `MinMaxResult` like for `minmax()`. /// /// For the minimum, the first minimal element is returned. For the maximum, - /// the last maximal element wins. This matches the behavior of the standard + /// the last maximal element wins. This matches the behavior of the standard /// `Iterator::min()` and `Iterator::max()` methods. /// /// The keys can be floats but no particular result is guaranteed @@ -2317,7 +2350,7 @@ pub trait Itertools : Iterator { /// The return value is a variant of `MinMaxResult` like for `minmax()`. /// /// For the minimum, the first minimal element is returned. For the maximum, - /// the last maximal element wins. This matches the behavior of the standard + /// the last maximal element wins. This matches the behavior of the standard /// `Iterator::min()` and `Iterator::max()` methods. fn minmax_by(self, mut compare: F) -> MinMaxResult where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering diff --git a/src/range.rs b/src/range.rs new file mode 100644 index 000000000..3f42fbbd8 --- /dev/null +++ b/src/range.rs @@ -0,0 +1,82 @@ +use core::ops::{ RangeBounds, Bound }; +use core::iter::FusedIterator; +use crate::Itertools; + +/// An iterator over a range of values. +/// +/// Acquired by the [`range`] function or the +/// [`Itertools::range`] method. +pub struct Range { + range: R, + internal: I, + counter: usize, +} + +impl Clone for Range + where I: Clone, R: Clone +{ + fn clone(&self) -> Self { + Range { + counter: self.counter, + range: self.range.clone(), + internal: self.internal.clone(), + } + } +} + +impl Iterator for Range + where I: Iterator, + R: RangeBounds +{ + type Item = T; + + fn next(&mut self) -> Option { + if self.counter == 0 { + match self.range.start_bound() { + Bound::Included(&n) => { + (0..n).for_each(|_| { self.internal.next(); }); + self.counter = n; + }, + Bound::Excluded(&n) => { + (0..=n).for_each(|_| { self.internal.next(); }); + self.counter = n + 1; + }, + Bound::Unbounded => (), + } + } + + match self.range.end_bound() { + Bound::Unbounded => self.internal.next(), + Bound::Included(&n) => { + if self.counter > n { return None; } + + self.counter += 1; + self.internal.next() + }, + Bound::Excluded(&n) => { + if self.counter >= n { return None; } + + self.counter += 1; + self.internal.next() + }, + } + } +} + +impl FusedIterator for Range +where I: Iterator + FusedIterator, + R: RangeBounds {} + +/// Limits an iterator to a range. See [`Itertools::range`] +/// for more information. +pub fn range(iter: I, range: R) + -> Range + where I: Iterator, + R: RangeBounds +{ + Range { + internal: iter, + range: range, + counter: 0, + } +} From 50e6b491b42b257c39a3db70add508d84363398b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Fri, 5 Jun 2020 16:50:16 +0200 Subject: [PATCH 02/12] Added size_hint implementation to Range iterator --- src/lib.rs | 2 ++ src/range.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 2694dbb55..c2f9a59d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -450,6 +450,8 @@ pub trait Itertools : Iterator { /// Similar to [`Iterator::skip`] and [`Iterator::take`], /// but some may consider it to be more readable. /// + /// # Examples + /// /// ``` /// use itertools::Itertools; /// diff --git a/src/range.rs b/src/range.rs index 3f42fbbd8..ad270881c 100644 --- a/src/range.rs +++ b/src/range.rs @@ -1,7 +1,11 @@ use core::ops::{ RangeBounds, Bound }; -use core::iter::FusedIterator; +use core::iter::{ExactSizeIterator, FusedIterator}; use crate::Itertools; +// We may want to allow this to become a double ended +// iterator if the thing it's iterating over is double ended, +// and if the range has a specified end point. + /// An iterator over a range of values. /// /// Acquired by the [`range`] function or the @@ -61,8 +65,91 @@ impl Iterator for Range }, } } + + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// assert_eq!( + /// (0..10).range(2..4).size_hint(), + /// (2, Some(2)) + /// ); + /// + /// assert_eq!( + /// (0..10).range(5..15).size_hint(), + /// (5, Some(5)) + /// ); + /// + /// assert_eq!( + /// (0..10).range(2..).size_hint(), + /// (8, Some(8)) + /// ); + /// + /// assert_eq!( + /// (0..).range(..8).size_hint(), + /// (8, Some(8)) + /// ); + /// + /// assert_eq!( + /// (0..).range(..).size_hint(), + /// (std::usize::MAX, None) + /// ); + /// + /// assert_eq!( + /// (0..5).range(..).size_hint(), + /// (5, Some(5)) + /// ); + /// + /// assert_eq!( + /// (0..).range(5..10).size_hint(), + /// (5, Some(5)) + /// ); + /// + /// assert_eq!( + /// (0..).range(..10).size_hint(), + /// (10, Some(10)) + /// ); + /// ``` + fn size_hint(&self) -> (usize, Option) { + // Absolute mind melt, yes + let (pre_lower, pre_upper) = self.internal.size_hint(); + + let start = match self.range.start_bound() { + Bound::Included(&n) => n, + Bound::Excluded(&n) => n + 1, + Bound::Unbounded => 0, + }; + let end = match self.range.end_bound() { + Bound::Included(&n) => Some(n + 1), + Bound::Excluded(&n) => Some(n), + Bound::Unbounded => None, + }; + + let lower = match end { + Some(end) => + pre_lower.min(end).saturating_sub(start), + None => pre_lower.saturating_sub(start), + }; + + let upper = match (end, pre_upper) { + (Some(end), Some(pre_upper)) => + Some(pre_upper.min(end).saturating_sub(start)), + (Some(end), None) => + Some(end - start), + (None, Some(pre_upper)) => + Some(pre_upper.saturating_sub(start)), + (None, None) => None, + }; + + (lower, upper) + } } +impl ExactSizeIterator for Range +where I: Iterator + ExactSizeIterator, + R: RangeBounds {} + impl FusedIterator for Range where I: Iterator + FusedIterator, R: RangeBounds {} From 061acfb7fd1b398224e9e2e8fdae8fbdf21f5731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Fri, 5 Jun 2020 20:41:21 +0200 Subject: [PATCH 03/12] Reverted formatting changes in lib.rs --- src/lib.rs | 307 ++++++++++++++++++++++++++--------------------------- 1 file changed, 153 insertions(+), 154 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c2f9a59d1..629c395e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,7 @@ //! use itertools::interleave; //! //! for elt in interleave(&[1, 2, 3], &[2, 3, 4]) { -//! /* loop body */ +//! /* loop body */ //! } //! ``` //! @@ -37,8 +37,8 @@ //! - `use_std` //! - Enabled by default. //! - Disable to compile itertools using `#![no_std]`. This disables -//! any items that depend on collections (like `group_by`, `unique`, -//! `kmerge`, `join` and many more). +//! any items that depend on collections (like `group_by`, `unique`, +//! `kmerge`, `join` and many more). //! //! ## Rust Version //! @@ -138,7 +138,6 @@ pub mod structs { pub use crate::zip_eq_impl::ZipEq; pub use crate::zip_longest::ZipLongest; pub use crate::ziptuple::Zip; - pub use crate::range::Range; } /// Traits helpful for using certain `Itertools` methods in generic contexts. @@ -158,11 +157,11 @@ pub use crate::minmax::MinMaxResult; pub use crate::peeking_take_while::PeekingNext; pub use crate::process_results_impl::process_results; pub use crate::repeatn::repeat_n; +pub use crate::range::Range; #[allow(deprecated)] pub use crate::sources::{repeat_call, unfold, iterate}; pub use crate::with_position::Position; pub use crate::ziptuple::multizip; -pub use crate::range::range; mod adaptors; mod either_or_both; pub use crate::either_or_both::EitherOrBoth; @@ -178,6 +177,7 @@ mod combinations; mod combinations_with_replacement; mod exactly_one_err; mod diff; +mod range; mod format; #[cfg(feature = "use_std")] mod group_map; @@ -215,7 +215,6 @@ mod with_position; mod zip_eq_impl; mod zip_longest; mod ziptuple; -mod range; #[macro_export] /// Create an iterator over the “cartesian product” of iterators. @@ -283,7 +282,7 @@ macro_rules! iproduct { /// let inputs = [3, 7, 9, 6]; /// /// for (r, index, input) in izip!(&mut results, 0..10, &inputs) { -/// *r = index * 10 + input; +/// *r = index * 10 + input; /// } /// /// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]); @@ -399,6 +398,38 @@ pub trait Itertools : Iterator { intersperse::intersperse(self, element) } + /// Limits an iterator to a given range. + /// Similar to [`Iterator::skip`] and [`Iterator::take`], + /// but some may consider it to be more readable. + /// + /// # Examples + /// + /// ``` + /// use itertools::Itertools; + /// + /// let vec = vec![3, 1, 4, 1, 5]; + /// + /// let mut range: Vec<_> = + /// vec.iter().range(1..=3).copied().collect(); + /// assert_eq!(&range, &[1, 4, 1]); + /// + /// // It works with other types of ranges, too + /// range = vec.iter().range(..2).copied().collect(); + /// assert_eq!(&range, &[3, 1]); + /// + /// range = vec.iter().range(2..).copied().collect(); + /// assert_eq!(&range, &[4, 1, 5]); + /// + /// range = vec.iter().range(..).copied().collect(); + /// assert_eq!(range, vec); + /// ``` + fn range(self, r: R) -> Range + where R: core::ops::RangeBounds, + Self: Sized + { + range::range(self, r) + } + /// Create an iterator which iterates over both this and the specified /// iterator simultaneously, yielding pairs of two optional elements. /// @@ -446,38 +477,6 @@ pub trait Itertools : Iterator { zip_eq(self, other) } - /// Limits an iterator to a given range. - /// Similar to [`Iterator::skip`] and [`Iterator::take`], - /// but some may consider it to be more readable. - /// - /// # Examples - /// - /// ``` - /// use itertools::Itertools; - /// - /// let vec = vec![3, 1, 4, 1, 5]; - /// - /// let mut range: Vec<_> = - /// vec.iter().range(1..=3).copied().collect(); - /// assert_eq!(&range, &[1, 4, 1]); - /// - /// // It works with other types of ranges, too - /// range = vec.iter().range(..2).copied().collect(); - /// assert_eq!(&range, &[3, 1]); - /// - /// range = vec.iter().range(2..).copied().collect(); - /// assert_eq!(&range, &[4, 1, 5]); - /// - /// range = vec.iter().range(..).copied().collect(); - /// assert_eq!(range, vec); - /// ``` - fn range(self, r: R) -> Range - where R: core::ops::RangeBounds, - Self: Sized - { - range::range(self, r) - } - /// A “meta iterator adaptor”. Its closure receives a reference to the /// iterator and may pick off as many elements as it likes, to produce the /// next iterator element. @@ -489,14 +488,14 @@ pub trait Itertools : Iterator { /// /// // An adaptor that gathers elements in pairs /// let pit = (0..4).batching(|it| { - /// match it.next() { - /// None => None, - /// Some(x) => match it.next() { - /// None => None, - /// Some(y) => Some((x, y)), - /// } - /// } - /// }); + /// match it.next() { + /// None => None, + /// Some(x) => match it.next() { + /// None => None, + /// Some(y) => Some((x, y)), + /// } + /// } + /// }); /// /// itertools::assert_equal(pit, vec![(0, 1), (2, 3)]); /// ``` @@ -532,13 +531,13 @@ pub trait Itertools : Iterator { /// /// // group data into runs of larger than zero or not. /// let data = vec![1, 3, -2, -2, 1, 0, 1, 2]; - /// // groups: |---->|------>|--------->| + /// // groups: |---->|------>|--------->| /// /// // Note: The `&` is significant here, `GroupBy` is iterable /// // only by reference. You can also call `.into_iter()` explicitly. /// let mut data_grouped = Vec::new(); /// for (key, group) in &data.into_iter().group_by(|elt| *elt >= 0) { - /// data_grouped.push((key, group.collect())); + /// data_grouped.push((key, group.collect())); /// } /// assert_eq!(data_grouped, vec![(true, vec![1, 3]), (false, vec![-2, -2]), (true, vec![1, 0, 1, 2])]); /// ``` @@ -574,8 +573,8 @@ pub trait Itertools : Iterator { /// // Note: The `&` is significant here, `IntoChunks` is iterable /// // only by reference. You can also call `.into_iter()` explicitly. /// for chunk in &data.into_iter().chunks(3) { - /// // Check that the sum of each chunk is 4. - /// assert_eq!(4, chunk.sum()); + /// // Check that the sum of each chunk is 4. + /// assert_eq!(4, chunk.sum()); /// } /// ``` #[cfg(feature = "use_std")] @@ -597,7 +596,7 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// let mut v = Vec::new(); /// for (a, b) in (1..5).tuple_windows() { - /// v.push((a, b)); + /// v.push((a, b)); /// } /// assert_eq!(v, vec![(1, 2), (2, 3), (3, 4)]); /// @@ -637,7 +636,7 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// let mut v = Vec::new(); /// for (a, b) in (1..5).circular_tuple_windows() { - /// v.push((a, b)); + /// v.push((a, b)); /// } /// assert_eq!(v, vec![(1, 2), (2, 3), (3, 4), (4, 1)]); /// @@ -668,7 +667,7 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// let mut v = Vec::new(); /// for (a, b) in (1..5).tuples() { - /// v.push((a, b)); + /// v.push((a, b)); /// } /// assert_eq!(v, vec![(1, 2), (3, 4)]); /// @@ -836,7 +835,7 @@ pub trait Itertools : Iterator { /// and remove `i` from its source iterator /// - Emit `EitherOrBoth::Right(j)` when `i > j`, /// and remove `j` from its source iterator - /// - Emit `EitherOrBoth::Both(i, j)` when `i == j`, + /// - Emit `EitherOrBoth::Both(i, j)` when `i == j`, /// and remove both `i` and `j` from their respective source iterators /// /// ``` @@ -846,11 +845,11 @@ pub trait Itertools : Iterator { /// let ki = (0..10).step(3); /// let ku = (0..10).step(5); /// let ki_ku = ki.merge_join_by(ku, |i, j| i.cmp(j)).map(|either| { - /// match either { - /// Left(_) => "Ki", - /// Right(_) => "Ku", - /// Both(_, _) => "KiKu" - /// } + /// match either { + /// Left(_) => "Ki", + /// Right(_) => "Ku", + /// Both(_, _) => "KiKu" + /// } /// }); /// /// itertools::assert_equal(ki_ku, vec!["KiKu", "Ki", "Ku", "Ki", "Ki"]); @@ -954,7 +953,7 @@ pub trait Itertools : Iterator { /// ``` /// use itertools::Itertools; /// let mut multi_prod = (0..3).map(|i| (i * 2)..(i * 2 + 2)) - /// .multi_cartesian_product(); + /// .multi_cartesian_product(); /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 4])); /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 5])); /// assert_eq!(multi_prod.next(), Some(vec![0, 3, 4])); @@ -996,12 +995,12 @@ pub trait Itertools : Iterator { /// // sum same-sign runs together /// let data = vec![-1., -2., -3., 3., 1., 0., -1.]; /// itertools::assert_equal(data.into_iter().coalesce(|x, y| - /// if (x >= 0.) == (y >= 0.) { - /// Ok(x + y) - /// } else { - /// Err((x, y)) - /// }), - /// vec![-6., 4., -1.]); + /// if (x >= 0.) == (y >= 0.) { + /// Ok(x + y) + /// } else { + /// Err((x, y)) + /// }), + /// vec![-6., 4., -1.]); /// ``` fn coalesce(self, f: F) -> Coalesce where Self: Sized, @@ -1023,7 +1022,7 @@ pub trait Itertools : Iterator { /// /// let data = vec![1., 1., 2., 3., 3., 2., 2.]; /// itertools::assert_equal(data.into_iter().dedup(), - /// vec![1., 2., 3., 2.]); + /// vec![1., 2., 3., 2.]); /// ``` fn dedup(self) -> Dedup where Self: Sized, @@ -1045,7 +1044,7 @@ pub trait Itertools : Iterator { /// /// let data = vec![(0, 1.), (1, 1.), (0, 2.), (0, 3.), (1, 3.), (1, 2.), (2, 2.)]; /// itertools::assert_equal(data.into_iter().dedup_by(|x, y| x.1 == y.1), - /// vec![(0, 1.), (0, 2.), (0, 3.), (1, 2.)]); + /// vec![(0, 1.), (0, 2.), (0, 3.), (1, 2.)]); /// ``` fn dedup_by(self, cmp: Cmp) -> DedupBy where Self: Sized, @@ -1067,7 +1066,7 @@ pub trait Itertools : Iterator { /// /// let data = vec![1., 1., 2., 3., 3., 2., 2.]; /// itertools::assert_equal(data.into_iter().dedup_with_count(), - /// vec![(2, 1.), (1, 2.), (2, 3.), (2, 2.)]); + /// vec![(2, 1.), (1, 2.), (2, 3.), (2, 2.)]); /// ``` fn dedup_with_count(self) -> DedupWithCount where Self: Sized, @@ -1089,7 +1088,7 @@ pub trait Itertools : Iterator { /// /// let data = vec![(0, 1.), (1, 1.), (0, 2.), (0, 3.), (1, 3.), (1, 2.), (2, 2.)]; /// itertools::assert_equal(data.into_iter().dedup_by_with_count(|x, y| x.1 == y.1), - /// vec![(2, (0, 1.)), (1, (0, 2.)), (2, (0, 3.)), (2, (1, 2.))]); + /// vec![(2, (0, 1.)), (1, (0, 2.)), (2, (0, 3.)), (2, (1, 2.))]); /// ``` fn dedup_by_with_count(self, cmp: Cmp) -> DedupByWithCount where Self: Sized, @@ -1114,7 +1113,7 @@ pub trait Itertools : Iterator { /// /// let data = vec![10, 20, 30, 20, 40, 10, 50]; /// itertools::assert_equal(data.into_iter().unique(), - /// vec![10, 20, 30, 40, 50]); + /// vec![10, 20, 30, 40, 50]); /// ``` #[cfg(feature = "use_std")] fn unique(self) -> Unique @@ -1140,7 +1139,7 @@ pub trait Itertools : Iterator { /// /// let data = vec!["a", "bb", "aa", "c", "ccc"]; /// itertools::assert_equal(data.into_iter().unique_by(|s| s.len()), - /// vec!["a", "bb", "ccc"]); + /// vec!["a", "bb", "ccc"]); /// ``` #[cfg(feature = "use_std")] fn unique_by(self, f: F) -> UniqueBy @@ -1183,7 +1182,7 @@ pub trait Itertools : Iterator { /// let mut hexadecimals = "0123456789abcdef".chars(); /// /// let decimals = hexadecimals.take_while_ref(|c| c.is_numeric()) - /// .collect::(); + /// .collect::(); /// assert_eq!(decimals, "0123456789"); /// assert_eq!(hexadecimals.next(), Some('a')); /// @@ -1205,8 +1204,8 @@ pub trait Itertools : Iterator { /// /// // List all hexadecimal digits /// itertools::assert_equal( - /// (0..).map(|i| std::char::from_digit(i, 16)).while_some(), - /// "0123456789abcdef".chars()); + /// (0..).map(|i| std::char::from_digit(i, 16)).while_some(), + /// "0123456789abcdef".chars()); /// /// ``` fn while_some(self) -> WhileSome @@ -1226,7 +1225,7 @@ pub trait Itertools : Iterator { /// /// let mut v = Vec::new(); /// for (a, b) in (1..5).tuple_combinations() { - /// v.push((a, b)); + /// v.push((a, b)); /// } /// assert_eq!(v, vec![(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]); /// @@ -1267,10 +1266,10 @@ pub trait Itertools : Iterator { /// /// let it = (1..5).combinations(3); /// itertools::assert_equal(it, vec![ - /// vec![1, 2, 3], - /// vec![1, 2, 4], - /// vec![1, 3, 4], - /// vec![2, 3, 4], + /// vec![1, 2, 3], + /// vec![1, 2, 4], + /// vec![1, 3, 4], + /// vec![2, 3, 4], /// ]); /// ``` /// @@ -1280,9 +1279,9 @@ pub trait Itertools : Iterator { /// /// let it = vec![1, 2, 2].into_iter().combinations(2); /// itertools::assert_equal(it, vec![ - /// vec![1, 2], // Note: these are the same - /// vec![1, 2], // Note: these are the same - /// vec![2, 2], + /// vec![1, 2], // Note: these are the same + /// vec![1, 2], // Note: these are the same + /// vec![2, 2], /// ]); /// ``` #[cfg(feature = "use_std")] @@ -1304,12 +1303,12 @@ pub trait Itertools : Iterator { /// /// let it = (1..4).combinations_with_replacement(2); /// itertools::assert_equal(it, vec![ - /// vec![1, 1], - /// vec![1, 2], - /// vec![1, 3], - /// vec![2, 2], - /// vec![2, 3], - /// vec![3, 3], + /// vec![1, 1], + /// vec![1, 2], + /// vec![1, 3], + /// vec![2, 2], + /// vec![2, 3], + /// vec![3, 3], /// ]); /// ``` #[cfg(feature = "use_std")] @@ -1335,12 +1334,12 @@ pub trait Itertools : Iterator { /// /// let perms = (5..8).permutations(2); /// itertools::assert_equal(perms, vec![ - /// vec![5, 6], - /// vec![5, 7], - /// vec![6, 5], - /// vec![6, 7], - /// vec![7, 5], - /// vec![7, 6], + /// vec![5, 6], + /// vec![5, 7], + /// vec![6, 5], + /// vec![6, 7], + /// vec![7, 5], + /// vec![7, 6], /// ]); /// ``` /// @@ -1351,8 +1350,8 @@ pub trait Itertools : Iterator { /// /// let it = vec![2, 2].into_iter().permutations(2); /// itertools::assert_equal(it, vec![ - /// vec![2, 2], // Note: these are the same - /// vec![2, 2], // Note: these are the same + /// vec![2, 2], // Note: these are the same + /// vec![2, 2], // Note: these are the same /// ]); /// ``` /// @@ -1401,10 +1400,10 @@ pub trait Itertools : Iterator { /// /// let it = (0..4).with_position(); /// itertools::assert_equal(it, - /// vec![Position::First(0), - /// Position::Middle(1), - /// Position::Middle(2), - /// Position::Last(3)]); + /// vec![Position::First(0), + /// Position::Middle(1), + /// Position::Middle(2), + /// Position::Last(3)]); /// /// let it = (0..1).with_position(); /// itertools::assert_equal(it, vec![Position::Only(0)]); @@ -1486,9 +1485,9 @@ pub trait Itertools : Iterator { /// let iter = 1..3; /// /// if let Some((x, y)) = iter.collect_tuple() { - /// assert_eq!((x, y), (1, 2)) + /// assert_eq!((x, y), (1, 2)) /// } else { - /// panic!("Expected two elements") + /// panic!("Expected two elements") /// } /// ``` fn collect_tuple(mut self) -> Option @@ -1639,7 +1638,7 @@ pub trait Itertools : Iterator { /// /// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]]; /// assert_eq!(input.into_iter().concat(), - /// vec![1, 2, 3, 4, 5, 6]); + /// vec![1, 2, 3, 4, 5, 6]); /// ``` fn concat(self) -> Self::Item where Self: Sized, @@ -1667,14 +1666,14 @@ pub trait Itertools : Iterator { /// use itertools::Itertools; /// /// fn process_dir_entries(entries: &[fs::DirEntry]) { - /// // ... + /// // ... /// } /// /// fn do_stuff() -> std::io::Result<()> { - /// let entries: Vec<_> = fs::read_dir(".")?.try_collect()?; - /// process_dir_entries(&entries); + /// let entries: Vec<_> = fs::read_dir(".")?.try_collect()?; + /// process_dir_entries(&entries); /// - /// Ok(()) + /// Ok(()) /// } /// ``` #[cfg(feature = "use_std")] @@ -1759,8 +1758,8 @@ pub trait Itertools : Iterator { /// /// let data = [1.1, 2.71828, -3.]; /// assert_eq!( - /// format!("{:.2}", data.iter().format(", ")), - /// "1.10, 2.72, -3.00"); + /// format!("{:.2}", data.iter().format(", ")), + /// "1.10, 2.72, -3.00"); /// ``` fn format(self, sep: &str) -> Format where Self: Sized, @@ -1787,16 +1786,16 @@ pub trait Itertools : Iterator { /// let data = [1.1, 2.71828, -3.]; /// let data_formatter = data.iter().format_with(", ", |elt, f| f(&format_args!("{:.2}", elt))); /// assert_eq!(format!("{}", data_formatter), - /// "1.10, 2.72, -3.00"); + /// "1.10, 2.72, -3.00"); /// /// // .format_with() is recursively composable /// let matrix = [[1., 2., 3.], - /// [4., 5., 6.]]; + /// [4., 5., 6.]]; /// let matrix_formatter = matrix.iter().format_with("\n", |row, f| { - /// f(&row.iter().format_with(", ", |elt, g| g(&elt))) - /// }); + /// f(&row.iter().format_with(", ", |elt, g| g(&elt))) + /// }); /// assert_eq!(format!("{}", matrix_formatter), - /// "1, 2, 3\n4, 5, 6"); + /// "1, 2, 3\n4, 5, 6"); /// /// /// ``` @@ -1837,16 +1836,16 @@ pub trait Itertools : Iterator { /// /// let values = [1, 2, -2, -1, 2, 1]; /// assert_eq!( - /// values.iter() - /// .map(Ok::<_, ()>) - /// .fold_results(0, Add::add), - /// Ok(3) + /// values.iter() + /// .map(Ok::<_, ()>) + /// .fold_results(0, Add::add), + /// Ok(3) /// ); /// assert!( - /// values.iter() - /// .map(|&x| if x >= 0 { Ok(x) } else { Err("Negative number") }) - /// .fold_results(0, Add::add) - /// .is_err() + /// values.iter() + /// .map(|&x| if x >= 0 { Ok(x) } else { Err("Negative number") }) + /// .fold_results(0, Add::add) + /// .is_err() /// ); /// ``` fn fold_results(&mut self, mut start: B, mut f: F) -> Result @@ -1928,8 +1927,8 @@ pub trait Itertools : Iterator { /// └─f └─f └─f │ /// │ │ │ │ /// └───f └─f - /// │ │ - /// └─────f + /// │ │ + /// └─────f /// ``` /// /// Which, for non-associative functions, will typically produce a different @@ -1949,17 +1948,17 @@ pub trait Itertools : Iterator { /// // The same tree as above /// let num_strings = (1..8).map(|x| x.to_string()); /// assert_eq!(num_strings.tree_fold1(|x, y| format!("f({}, {})", x, y)), - /// Some(String::from("f(f(f(1, 2), f(3, 4)), f(f(5, 6), 7))"))); + /// Some(String::from("f(f(f(1, 2), f(3, 4)), f(f(5, 6), 7))"))); /// /// // Like fold1, an empty iterator produces None /// assert_eq!((0..0).tree_fold1(|x, y| x * y), None); /// /// // tree_fold1 matches fold1 for associative operations... /// assert_eq!((0..10).tree_fold1(|x, y| x + y), - /// (0..10).fold1(|x, y| x + y)); + /// (0..10).fold1(|x, y| x + y)); /// // ...but not for non-associative ones /// assert_ne!((0..10).tree_fold1(|x, y| x - y), - /// (0..10).fold1(|x, y| x - y)); + /// (0..10).fold1(|x, y| x - y)); /// ``` fn tree_fold1(mut self, mut f: F) -> Option where F: FnMut(Self::Item, Self::Item) -> Self::Item, @@ -2004,7 +2003,7 @@ pub trait Itertools : Iterator { Ok(y) => x = f(x, y), // If we ran out of items, combine whatever we did manage - // to get. It's better combined with the current value + // to get. It's better combined with the current value // than something in a parent frame, because the tree in // the parent is always as least as big as this one. Err(None) => return Err(Some(x)), @@ -2035,20 +2034,20 @@ pub trait Itertools : Iterator { /// /// // for loop: /// for i in &numbers { - /// if *i > 5 { - /// break; - /// } - /// result = result + i; + /// if *i > 5 { + /// break; + /// } + /// result = result + i; /// } /// /// // fold: /// let result2 = numbers.iter().fold(0, |acc, x| { - /// if *x > 5 { acc } else { acc + x } + /// if *x > 5 { acc } else { acc + x } /// }); /// /// // fold_while: /// let result3 = numbers.iter().fold_while(0, |acc, x| { - /// if *x > 5 { Done(acc) } else { Continue(acc + x) } + /// if *x > 5 { Done(acc) } else { Continue(acc + x) } /// }).into_inner(); /// /// // they're the same @@ -2147,7 +2146,7 @@ pub trait Itertools : Iterator { /// // sort the letters of the text in ascending order /// let text = "bdacfe"; /// itertools::assert_equal(text.chars().sorted(), - /// "abcdef".chars()); + /// "abcdef".chars()); /// ``` #[cfg(feature = "use_std")] fn sorted(self) -> VecIntoIter @@ -2177,12 +2176,12 @@ pub trait Itertools : Iterator { /// let people = vec![("Jane", 20), ("John", 18), ("Jill", 30), ("Jack", 27)]; /// /// let oldest_people_first = people - /// .into_iter() - /// .sorted_by(|a, b| Ord::cmp(&b.1, &a.1)) - /// .map(|(person, _age)| person); + /// .into_iter() + /// .sorted_by(|a, b| Ord::cmp(&b.1, &a.1)) + /// .map(|(person, _age)| person); /// /// itertools::assert_equal(oldest_people_first, - /// vec!["Jill", "Jack", "Jane", "John"]); + /// vec!["Jill", "Jack", "Jane", "John"]); /// ``` #[cfg(feature = "use_std")] fn sorted_by(self, cmp: F) -> VecIntoIter @@ -2210,12 +2209,12 @@ pub trait Itertools : Iterator { /// let people = vec![("Jane", 20), ("John", 18), ("Jill", 30), ("Jack", 27)]; /// /// let oldest_people_first = people - /// .into_iter() - /// .sorted_by_key(|x| -x.1) - /// .map(|(person, _age)| person); + /// .into_iter() + /// .sorted_by_key(|x| -x.1) + /// .map(|(person, _age)| person); /// /// itertools::assert_equal(oldest_people_first, - /// vec!["Jill", "Jack", "Jane", "John"]); + /// vec!["Jill", "Jack", "Jane", "John"]); /// ``` #[cfg(feature = "use_std")] fn sorted_by_key(self, f: F) -> VecIntoIter @@ -2238,13 +2237,13 @@ pub trait Itertools : Iterator { /// let successes_and_failures = vec![Ok(1), Err(false), Err(true), Ok(2)]; /// /// let (successes, failures): (Vec<_>, Vec<_>) = successes_and_failures - /// .into_iter() - /// .partition_map(|r| { - /// match r { - /// Ok(v) => Either::Left(v), - /// Err(v) => Either::Right(v), - /// } - /// }); + /// .into_iter() + /// .partition_map(|r| { + /// match r { + /// Ok(v) => Either::Left(v), + /// Err(v) => Either::Right(v), + /// } + /// }); /// /// assert_eq!(successes, [1, 2]); /// assert_eq!(failures, [false, true]); @@ -2335,7 +2334,7 @@ pub trait Itertools : Iterator { /// The return value is a variant of `MinMaxResult` like for `minmax()`. /// /// For the minimum, the first minimal element is returned. For the maximum, - /// the last maximal element wins. This matches the behavior of the standard + /// the last maximal element wins. This matches the behavior of the standard /// `Iterator::min()` and `Iterator::max()` methods. /// /// The keys can be floats but no particular result is guaranteed @@ -2352,7 +2351,7 @@ pub trait Itertools : Iterator { /// The return value is a variant of `MinMaxResult` like for `minmax()`. /// /// For the minimum, the first minimal element is returned. For the maximum, - /// the last maximal element wins. This matches the behavior of the standard + /// the last maximal element wins. This matches the behavior of the standard /// `Iterator::min()` and `Iterator::max()` methods. fn minmax_by(self, mut compare: F) -> MinMaxResult where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering From 6d624b7bd6aec92b0af67aa1d1a5dc7053b7069c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Fri, 5 Jun 2020 21:20:23 +0200 Subject: [PATCH 04/12] Changed range to use a trait and existing iter functions --- src/lib.rs | 13 ++-- src/range.rs | 203 +++++++++++++++------------------------------------ 2 files changed, 68 insertions(+), 148 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 629c395e6..a0078e729 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -157,7 +157,6 @@ pub use crate::minmax::MinMaxResult; pub use crate::peeking_take_while::PeekingNext; pub use crate::process_results_impl::process_results; pub use crate::repeatn::repeat_n; -pub use crate::range::Range; #[allow(deprecated)] pub use crate::sources::{repeat_call, unfold, iterate}; pub use crate::with_position::Position; @@ -416,6 +415,9 @@ pub trait Itertools : Iterator { /// // It works with other types of ranges, too /// range = vec.iter().range(..2).copied().collect(); /// assert_eq!(&range, &[3, 1]); + /// + /// range = vec.iter().range(0..1).copied().collect(); + /// assert_eq!(&range, &[3]); /// /// range = vec.iter().range(2..).copied().collect(); /// assert_eq!(&range, &[4, 1, 5]); @@ -423,11 +425,12 @@ pub trait Itertools : Iterator { /// range = vec.iter().range(..).copied().collect(); /// assert_eq!(range, vec); /// ``` - fn range(self, r: R) -> Range - where R: core::ops::RangeBounds, - Self: Sized + fn range(self, range: R) + -> R::IterTo + where R: range::IntoRangeIter, + Self: Sized { - range::range(self, r) + range::range(self, range) } /// Create an iterator which iterates over both this and the specified diff --git a/src/range.rs b/src/range.rs index ad270881c..391b52c6e 100644 --- a/src/range.rs +++ b/src/range.rs @@ -1,169 +1,86 @@ -use core::ops::{ RangeBounds, Bound }; -use core::iter::{ExactSizeIterator, FusedIterator}; +use core::ops::{ Range, RangeTo, RangeFrom, RangeFull, RangeInclusive, RangeToInclusive }; +use core::iter::{Skip, Take}; use crate::Itertools; -// We may want to allow this to become a double ended -// iterator if the thing it's iterating over is double ended, -// and if the range has a specified end point. +/// Used by the ``range`` function to know which iterator +/// to turn different ranges into. +pub trait IntoRangeIter { + type IterTo; -/// An iterator over a range of values. -/// -/// Acquired by the [`range`] function or the -/// [`Itertools::range`] method. -pub struct Range { - range: R, - internal: I, - counter: usize, + fn into_range_iter(self, from: IterFrom) -> Self::IterTo; } -impl Clone for Range - where I: Clone, R: Clone +impl IntoRangeIter for Range + where I: Iterator { - fn clone(&self) -> Self { - Range { - counter: self.counter, - range: self.range.clone(), - internal: self.internal.clone(), - } - } + type IterTo = Take>; + + fn into_range_iter(self, iter: I) -> Self::IterTo { + iter.skip(self.start) + .take(self.end.saturating_sub(self.start)) + } } -impl Iterator for Range - where I: Iterator, - R: RangeBounds +impl IntoRangeIter for RangeInclusive + where I: Iterator { - type Item = T; - - fn next(&mut self) -> Option { - if self.counter == 0 { - match self.range.start_bound() { - Bound::Included(&n) => { - (0..n).for_each(|_| { self.internal.next(); }); - self.counter = n; - }, - Bound::Excluded(&n) => { - (0..=n).for_each(|_| { self.internal.next(); }); - self.counter = n + 1; - }, - Bound::Unbounded => (), - } - } - - match self.range.end_bound() { - Bound::Unbounded => self.internal.next(), - Bound::Included(&n) => { - if self.counter > n { return None; } - - self.counter += 1; - self.internal.next() - }, - Bound::Excluded(&n) => { - if self.counter >= n { return None; } + type IterTo = Take>; + + fn into_range_iter(self, iter: I) -> Self::IterTo { + iter.skip(*self.start()) + .take( + (1 + *self.end()) + .saturating_sub(*self.start()) + ) + } +} - self.counter += 1; - self.internal.next() - }, - } - } +impl IntoRangeIter for RangeTo + where I: Iterator +{ + type IterTo = Take; - /// # Examples - /// - /// ``` - /// use itertools::Itertools; - /// - /// assert_eq!( - /// (0..10).range(2..4).size_hint(), - /// (2, Some(2)) - /// ); - /// - /// assert_eq!( - /// (0..10).range(5..15).size_hint(), - /// (5, Some(5)) - /// ); - /// - /// assert_eq!( - /// (0..10).range(2..).size_hint(), - /// (8, Some(8)) - /// ); - /// - /// assert_eq!( - /// (0..).range(..8).size_hint(), - /// (8, Some(8)) - /// ); - /// - /// assert_eq!( - /// (0..).range(..).size_hint(), - /// (std::usize::MAX, None) - /// ); - /// - /// assert_eq!( - /// (0..5).range(..).size_hint(), - /// (5, Some(5)) - /// ); - /// - /// assert_eq!( - /// (0..).range(5..10).size_hint(), - /// (5, Some(5)) - /// ); - /// - /// assert_eq!( - /// (0..).range(..10).size_hint(), - /// (10, Some(10)) - /// ); - /// ``` - fn size_hint(&self) -> (usize, Option) { - // Absolute mind melt, yes - let (pre_lower, pre_upper) = self.internal.size_hint(); + fn into_range_iter(self, iter: I) -> Self::IterTo { + iter.take(self.end) + } +} - let start = match self.range.start_bound() { - Bound::Included(&n) => n, - Bound::Excluded(&n) => n + 1, - Bound::Unbounded => 0, - }; - let end = match self.range.end_bound() { - Bound::Included(&n) => Some(n + 1), - Bound::Excluded(&n) => Some(n), - Bound::Unbounded => None, - }; +impl IntoRangeIter for RangeToInclusive + where I: Iterator +{ + type IterTo = Take; - let lower = match end { - Some(end) => - pre_lower.min(end).saturating_sub(start), - None => pre_lower.saturating_sub(start), - }; + fn into_range_iter(self, iter: I) -> Self::IterTo { + iter.take(self.end + 1) + } +} - let upper = match (end, pre_upper) { - (Some(end), Some(pre_upper)) => - Some(pre_upper.min(end).saturating_sub(start)), - (Some(end), None) => - Some(end - start), - (None, Some(pre_upper)) => - Some(pre_upper.saturating_sub(start)), - (None, None) => None, - }; +impl IntoRangeIter for RangeFrom + where I: Iterator +{ + type IterTo = Skip; - (lower, upper) + fn into_range_iter(self, iter: I) -> Self::IterTo { + iter.skip(self.start) } } -impl ExactSizeIterator for Range -where I: Iterator + ExactSizeIterator, - R: RangeBounds {} +impl IntoRangeIter for RangeFull + where I: Iterator +{ + type IterTo = I; -impl FusedIterator for Range -where I: Iterator + FusedIterator, - R: RangeBounds {} + fn into_range_iter(self, iter: I) -> Self::IterTo { + iter + } +} /// Limits an iterator to a range. See [`Itertools::range`] /// for more information. pub fn range(iter: I, range: R) - -> Range + -> R::IterTo where I: Iterator, - R: RangeBounds + R: IntoRangeIter { - Range { - internal: iter, - range: range, - counter: 0, - } + range.into_range_iter(iter) } From 14e34cfcfa7c48c869ce560ecd4a3f829b5cc51c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Fri, 5 Jun 2020 22:10:52 +0200 Subject: [PATCH 05/12] Change range function to use IntoIterator instead of Iterator --- src/range.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/range.rs b/src/range.rs index 391b52c6e..cc68cc705 100644 --- a/src/range.rs +++ b/src/range.rs @@ -79,8 +79,8 @@ impl IntoRangeIter for RangeFull /// for more information. pub fn range(iter: I, range: R) -> R::IterTo - where I: Iterator, - R: IntoRangeIter + where I: IntoIterator, + R: IntoRangeIter { - range.into_range_iter(iter) + range.into_range_iter(iter.into_iter()) } From f469a689a0634e0ad20fc72b28aba7987a54580f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Mon, 8 Jun 2020 14:24:49 +0200 Subject: [PATCH 06/12] Prevented more IntoRangeIter implementors --- src/lib.rs | 5 ++++- src/range.rs | 60 ++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a0078e729..938e34bc8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -424,9 +424,12 @@ pub trait Itertools : Iterator { /// /// range = vec.iter().range(..).copied().collect(); /// assert_eq!(range, vec); + /// + /// let value = vec.iter().range(3).copied(); + /// assert_eq!(value, Some(1)); /// ``` fn range(self, range: R) - -> R::IterTo + -> R::Output where R: range::IntoRangeIter, Self: Sized { diff --git a/src/range.rs b/src/range.rs index cc68cc705..a96114976 100644 --- a/src/range.rs +++ b/src/range.rs @@ -2,20 +2,38 @@ use core::ops::{ Range, RangeTo, RangeFrom, RangeFull, RangeInclusive, RangeToIn use core::iter::{Skip, Take}; use crate::Itertools; +mod private_into_range_iter { + use core::ops; + + pub trait Sealed {} + + impl Sealed for ops::Range {} + impl Sealed for ops::RangeInclusive {} + impl Sealed for ops::RangeTo {} + impl Sealed for ops::RangeToInclusive {} + impl Sealed for ops::RangeFrom {} + impl Sealed for ops::RangeFull {} + impl Sealed for usize {} +} + /// Used by the ``range`` function to know which iterator /// to turn different ranges into. -pub trait IntoRangeIter { - type IterTo; +pub trait IntoRangeIter : private_into_range_iter::Sealed { + type Output; - fn into_range_iter(self, from: IterFrom) -> Self::IterTo; + /// Returns an iterator(or value) in the specified range. + /// + /// Prefer calling [`range`] or [`Itertools::range`] instead + /// of calling this directly. + fn into_range_iter(self, from: T) -> Self::Output; } impl IntoRangeIter for Range where I: Iterator { - type IterTo = Take>; + type Output = Take>; - fn into_range_iter(self, iter: I) -> Self::IterTo { + fn into_range_iter(self, iter: I) -> Self::Output { iter.skip(self.start) .take(self.end.saturating_sub(self.start)) } @@ -24,9 +42,9 @@ impl IntoRangeIter for Range impl IntoRangeIter for RangeInclusive where I: Iterator { - type IterTo = Take>; + type Output = Take>; - fn into_range_iter(self, iter: I) -> Self::IterTo { + fn into_range_iter(self, iter: I) -> Self::Output { iter.skip(*self.start()) .take( (1 + *self.end()) @@ -38,9 +56,9 @@ impl IntoRangeIter for RangeInclusive impl IntoRangeIter for RangeTo where I: Iterator { - type IterTo = Take; + type Output = Take; - fn into_range_iter(self, iter: I) -> Self::IterTo { + fn into_range_iter(self, iter: I) -> Self::Output { iter.take(self.end) } } @@ -48,9 +66,9 @@ impl IntoRangeIter for RangeTo impl IntoRangeIter for RangeToInclusive where I: Iterator { - type IterTo = Take; + type Output = Take; - fn into_range_iter(self, iter: I) -> Self::IterTo { + fn into_range_iter(self, iter: I) -> Self::Output { iter.take(self.end + 1) } } @@ -58,9 +76,9 @@ impl IntoRangeIter for RangeToInclusive impl IntoRangeIter for RangeFrom where I: Iterator { - type IterTo = Skip; + type Output = Skip; - fn into_range_iter(self, iter: I) -> Self::IterTo { + fn into_range_iter(self, iter: I) -> Self::Output { iter.skip(self.start) } } @@ -68,17 +86,27 @@ impl IntoRangeIter for RangeFrom impl IntoRangeIter for RangeFull where I: Iterator { - type IterTo = I; + type Output = I; - fn into_range_iter(self, iter: I) -> Self::IterTo { + fn into_range_iter(self, iter: I) -> Self::Output { iter } } +impl IntoRangeIter for usize + where I: Iterator +{ + type Output = Option; + + fn into_range_iter(self, mut iter: I) -> Self::Output { + iter.nth(self) + } +} + /// Limits an iterator to a range. See [`Itertools::range`] /// for more information. pub fn range(iter: I, range: R) - -> R::IterTo + -> R::Output where I: IntoIterator, R: IntoRangeIter { From aa0ea02c7e9193091f3da53bd1dcbba84f089a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Mon, 8 Jun 2020 14:32:44 +0200 Subject: [PATCH 07/12] Renamed range to get --- src/{range.rs => iter_index.rs} | 40 ++++++++++++++++----------------- src/lib.rs | 25 ++++++++++----------- 2 files changed, 32 insertions(+), 33 deletions(-) rename src/{range.rs => iter_index.rs} (61%) diff --git a/src/range.rs b/src/iter_index.rs similarity index 61% rename from src/range.rs rename to src/iter_index.rs index a96114976..ff6dc4f26 100644 --- a/src/range.rs +++ b/src/iter_index.rs @@ -2,7 +2,7 @@ use core::ops::{ Range, RangeTo, RangeFrom, RangeFull, RangeInclusive, RangeToIn use core::iter::{Skip, Take}; use crate::Itertools; -mod private_into_range_iter { +mod private_iter_index { use core::ops; pub trait Sealed {} @@ -18,33 +18,33 @@ mod private_into_range_iter { /// Used by the ``range`` function to know which iterator /// to turn different ranges into. -pub trait IntoRangeIter : private_into_range_iter::Sealed { +pub trait IterIndex : private_iter_index::Sealed { type Output; /// Returns an iterator(or value) in the specified range. /// /// Prefer calling [`range`] or [`Itertools::range`] instead /// of calling this directly. - fn into_range_iter(self, from: T) -> Self::Output; + fn get(self, from: T) -> Self::Output; } -impl IntoRangeIter for Range +impl IterIndex for Range where I: Iterator { type Output = Take>; - fn into_range_iter(self, iter: I) -> Self::Output { + fn get(self, iter: I) -> Self::Output { iter.skip(self.start) .take(self.end.saturating_sub(self.start)) } } -impl IntoRangeIter for RangeInclusive +impl IterIndex for RangeInclusive where I: Iterator { type Output = Take>; - fn into_range_iter(self, iter: I) -> Self::Output { + fn get(self, iter: I) -> Self::Output { iter.skip(*self.start()) .take( (1 + *self.end()) @@ -53,62 +53,62 @@ impl IntoRangeIter for RangeInclusive } } -impl IntoRangeIter for RangeTo +impl IterIndex for RangeTo where I: Iterator { type Output = Take; - fn into_range_iter(self, iter: I) -> Self::Output { + fn get(self, iter: I) -> Self::Output { iter.take(self.end) } } -impl IntoRangeIter for RangeToInclusive +impl IterIndex for RangeToInclusive where I: Iterator { type Output = Take; - fn into_range_iter(self, iter: I) -> Self::Output { + fn get(self, iter: I) -> Self::Output { iter.take(self.end + 1) } } -impl IntoRangeIter for RangeFrom +impl IterIndex for RangeFrom where I: Iterator { type Output = Skip; - fn into_range_iter(self, iter: I) -> Self::Output { + fn get(self, iter: I) -> Self::Output { iter.skip(self.start) } } -impl IntoRangeIter for RangeFull +impl IterIndex for RangeFull where I: Iterator { type Output = I; - fn into_range_iter(self, iter: I) -> Self::Output { + fn get(self, iter: I) -> Self::Output { iter } } -impl IntoRangeIter for usize +impl IterIndex for usize where I: Iterator { type Output = Option; - fn into_range_iter(self, mut iter: I) -> Self::Output { + fn get(self, mut iter: I) -> Self::Output { iter.nth(self) } } /// Limits an iterator to a range. See [`Itertools::range`] /// for more information. -pub fn range(iter: I, range: R) +pub fn get(iter: I, range: R) -> R::Output where I: IntoIterator, - R: IntoRangeIter + R: IterIndex { - range.into_range_iter(iter.into_iter()) + range.get(iter.into_iter()) } diff --git a/src/lib.rs b/src/lib.rs index 938e34bc8..81d39cd26 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,6 +143,7 @@ pub mod structs { /// Traits helpful for using certain `Itertools` methods in generic contexts. pub mod traits { pub use crate::tuple_impl::HomogeneousTuple; + pub use crate::iter_index::IterIndex; } #[allow(deprecated)] @@ -176,7 +177,7 @@ mod combinations; mod combinations_with_replacement; mod exactly_one_err; mod diff; -mod range; +mod iter_index; mod format; #[cfg(feature = "use_std")] mod group_map; @@ -397,9 +398,7 @@ pub trait Itertools : Iterator { intersperse::intersperse(self, element) } - /// Limits an iterator to a given range. - /// Similar to [`Iterator::skip`] and [`Iterator::take`], - /// but some may consider it to be more readable. + /// Works similarly to [`slice::get`] but on iterators. /// /// # Examples /// @@ -409,31 +408,31 @@ pub trait Itertools : Iterator { /// let vec = vec![3, 1, 4, 1, 5]; /// /// let mut range: Vec<_> = - /// vec.iter().range(1..=3).copied().collect(); + /// vec.iter().get(1..=3).copied().collect(); /// assert_eq!(&range, &[1, 4, 1]); /// /// // It works with other types of ranges, too - /// range = vec.iter().range(..2).copied().collect(); + /// range = vec.iter().get(..2).copied().collect(); /// assert_eq!(&range, &[3, 1]); /// - /// range = vec.iter().range(0..1).copied().collect(); + /// range = vec.iter().get(0..1).copied().collect(); /// assert_eq!(&range, &[3]); /// - /// range = vec.iter().range(2..).copied().collect(); + /// range = vec.iter().get(2..).copied().collect(); /// assert_eq!(&range, &[4, 1, 5]); /// - /// range = vec.iter().range(..).copied().collect(); + /// range = vec.iter().get(..).copied().collect(); /// assert_eq!(range, vec); /// - /// let value = vec.iter().range(3).copied(); + /// let value = vec.iter().get(3).copied(); /// assert_eq!(value, Some(1)); /// ``` - fn range(self, range: R) + fn get(self, index: R) -> R::Output - where R: range::IntoRangeIter, + where R: iter_index::IterIndex, Self: Sized { - range::range(self, range) + iter_index::get(self, index) } /// Create an iterator which iterates over both this and the specified From 8ccd1c08270b77acf93673b622fa3946a897c754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Mon, 8 Jun 2020 14:58:14 +0200 Subject: [PATCH 08/12] Fixed up docs for get --- src/iter_index.rs | 14 +++++++++----- src/lib.rs | 13 ++++++++++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/iter_index.rs b/src/iter_index.rs index ff6dc4f26..ffc0a61fa 100644 --- a/src/iter_index.rs +++ b/src/iter_index.rs @@ -19,11 +19,13 @@ mod private_iter_index { /// Used by the ``range`` function to know which iterator /// to turn different ranges into. pub trait IterIndex : private_iter_index::Sealed { + /// The type that [`get`] or [`Itertools::get`] + /// returns when called with this type of index. type Output; /// Returns an iterator(or value) in the specified range. /// - /// Prefer calling [`range`] or [`Itertools::range`] instead + /// Prefer calling [`get`] or [`Itertools::get`] instead /// of calling this directly. fn get(self, from: T) -> Self::Output; } @@ -103,12 +105,14 @@ impl IterIndex for usize } } -/// Limits an iterator to a range. See [`Itertools::range`] -/// for more information. -pub fn get(iter: I, range: R) +/// Returns an element of the iterator or an iterator +/// over a subsection of the iterator. +/// +/// See [`Itertools::get`] for more information. +pub fn get(iter: I, index: R) -> R::Output where I: IntoIterator, R: IterIndex { - range.get(iter.into_iter()) + index.get(iter.into_iter()) } diff --git a/src/lib.rs b/src/lib.rs index 81d39cd26..cdd9949fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -158,6 +158,7 @@ pub use crate::minmax::MinMaxResult; pub use crate::peeking_take_while::PeekingNext; pub use crate::process_results_impl::process_results; pub use crate::repeatn::repeat_n; +pub use crate::iter_index::get; #[allow(deprecated)] pub use crate::sources::{repeat_call, unfold, iterate}; pub use crate::with_position::Position; @@ -398,7 +399,13 @@ pub trait Itertools : Iterator { intersperse::intersperse(self, element) } - /// Works similarly to [`slice::get`] but on iterators. + /// Returns an element at a specific location, or returns an iterator + /// over a subsection of the iterator. + /// + /// Works similarly to [`slice::get`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). + /// + /// It's a generalisation of [`take`], [`skip`] and [`nth`], and uses these + /// under the hood. /// /// # Examples /// @@ -427,6 +434,10 @@ pub trait Itertools : Iterator { /// let value = vec.iter().get(3).copied(); /// assert_eq!(value, Some(1)); /// ``` + /// + /// [`take`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take + /// [`skip`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.skip + /// [`nth`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.nth fn get(self, index: R) -> R::Output where R: iter_index::IterIndex, From eb326f0f7ed0d2f47b12f34e155f31fa3a790079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Mon, 8 Jun 2020 16:56:04 +0200 Subject: [PATCH 09/12] Made indentation all spaces --- src/iter_index.rs | 120 +++++++++++++++++++++++----------------------- src/lib.rs | 40 ++++++++-------- 2 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/iter_index.rs b/src/iter_index.rs index ffc0a61fa..8128ea172 100644 --- a/src/iter_index.rs +++ b/src/iter_index.rs @@ -3,106 +3,106 @@ use core::iter::{Skip, Take}; use crate::Itertools; mod private_iter_index { - use core::ops; + use core::ops; - pub trait Sealed {} + pub trait Sealed {} - impl Sealed for ops::Range {} - impl Sealed for ops::RangeInclusive {} - impl Sealed for ops::RangeTo {} - impl Sealed for ops::RangeToInclusive {} - impl Sealed for ops::RangeFrom {} - impl Sealed for ops::RangeFull {} - impl Sealed for usize {} + impl Sealed for ops::Range {} + impl Sealed for ops::RangeInclusive {} + impl Sealed for ops::RangeTo {} + impl Sealed for ops::RangeToInclusive {} + impl Sealed for ops::RangeFrom {} + impl Sealed for ops::RangeFull {} + impl Sealed for usize {} } /// Used by the ``range`` function to know which iterator /// to turn different ranges into. pub trait IterIndex : private_iter_index::Sealed { - /// The type that [`get`] or [`Itertools::get`] - /// returns when called with this type of index. - type Output; - - /// Returns an iterator(or value) in the specified range. - /// - /// Prefer calling [`get`] or [`Itertools::get`] instead - /// of calling this directly. - fn get(self, from: T) -> Self::Output; + /// The type that [`get`] or [`Itertools::get`] + /// returns when called with this type of index. + type Output; + + /// Returns an iterator(or value) in the specified range. + /// + /// Prefer calling [`get`] or [`Itertools::get`] instead + /// of calling this directly. + fn get(self, from: T) -> Self::Output; } impl IterIndex for Range - where I: Iterator + where I: Iterator { - type Output = Take>; + type Output = Take>; - fn get(self, iter: I) -> Self::Output { - iter.skip(self.start) - .take(self.end.saturating_sub(self.start)) - } + fn get(self, iter: I) -> Self::Output { + iter.skip(self.start) + .take(self.end.saturating_sub(self.start)) + } } impl IterIndex for RangeInclusive - where I: Iterator + where I: Iterator { - type Output = Take>; - - fn get(self, iter: I) -> Self::Output { - iter.skip(*self.start()) - .take( - (1 + *self.end()) - .saturating_sub(*self.start()) - ) - } + type Output = Take>; + + fn get(self, iter: I) -> Self::Output { + iter.skip(*self.start()) + .take( + (1 + *self.end()) + .saturating_sub(*self.start()) + ) + } } impl IterIndex for RangeTo - where I: Iterator + where I: Iterator { - type Output = Take; + type Output = Take; - fn get(self, iter: I) -> Self::Output { - iter.take(self.end) - } + fn get(self, iter: I) -> Self::Output { + iter.take(self.end) + } } impl IterIndex for RangeToInclusive - where I: Iterator + where I: Iterator { - type Output = Take; + type Output = Take; - fn get(self, iter: I) -> Self::Output { - iter.take(self.end + 1) - } + fn get(self, iter: I) -> Self::Output { + iter.take(self.end + 1) + } } impl IterIndex for RangeFrom - where I: Iterator + where I: Iterator { - type Output = Skip; + type Output = Skip; - fn get(self, iter: I) -> Self::Output { - iter.skip(self.start) - } + fn get(self, iter: I) -> Self::Output { + iter.skip(self.start) + } } impl IterIndex for RangeFull - where I: Iterator + where I: Iterator { - type Output = I; + type Output = I; - fn get(self, iter: I) -> Self::Output { - iter - } + fn get(self, iter: I) -> Self::Output { + iter + } } impl IterIndex for usize - where I: Iterator + where I: Iterator { - type Output = Option; + type Output = Option; - fn get(self, mut iter: I) -> Self::Output { - iter.nth(self) - } + fn get(self, mut iter: I) -> Self::Output { + iter.nth(self) + } } /// Returns an element of the iterator or an iterator @@ -114,5 +114,5 @@ pub fn get(iter: I, index: R) where I: IntoIterator, R: IterIndex { - index.get(iter.into_iter()) + index.get(iter.into_iter()) } diff --git a/src/lib.rs b/src/lib.rs index cdd9949fd..e7e4c06be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,7 +143,7 @@ pub mod structs { /// Traits helpful for using certain `Itertools` methods in generic contexts. pub mod traits { pub use crate::tuple_impl::HomogeneousTuple; - pub use crate::iter_index::IterIndex; + pub use crate::iter_index::IterIndex; } #[allow(deprecated)] @@ -399,16 +399,16 @@ pub trait Itertools : Iterator { intersperse::intersperse(self, element) } - /// Returns an element at a specific location, or returns an iterator - /// over a subsection of the iterator. - /// - /// Works similarly to [`slice::get`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). - /// - /// It's a generalisation of [`take`], [`skip`] and [`nth`], and uses these - /// under the hood. + /// Returns an element at a specific location, or returns an iterator + /// over a subsection of the iterator. + /// + /// Works similarly to [`slice::get`](https://doc.rust-lang.org/std/primitive.slice.html#method.get). + /// + /// It's a generalisation of [`take`], [`skip`] and [`nth`], and uses these + /// under the hood. + /// + /// # Examples /// - /// # Examples - /// /// ``` /// use itertools::Itertools; /// @@ -421,7 +421,7 @@ pub trait Itertools : Iterator { /// // It works with other types of ranges, too /// range = vec.iter().get(..2).copied().collect(); /// assert_eq!(&range, &[3, 1]); - /// + /// /// range = vec.iter().get(0..1).copied().collect(); /// assert_eq!(&range, &[3]); /// @@ -430,18 +430,18 @@ pub trait Itertools : Iterator { /// /// range = vec.iter().get(..).copied().collect(); /// assert_eq!(range, vec); - /// + /// /// let value = vec.iter().get(3).copied(); /// assert_eq!(value, Some(1)); /// ``` - /// - /// [`take`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take - /// [`skip`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.skip - /// [`nth`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.nth - fn get(self, index: R) - -> R::Output - where R: iter_index::IterIndex, - Self: Sized + /// + /// [`take`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take + /// [`skip`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.skip + /// [`nth`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.nth + fn get(self, index: R) + -> R::Output + where R: iter_index::IterIndex, + Self: Sized { iter_index::get(self, index) } From 52affb31880e02632a8e4cc71ff3fec09588b1ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Mon, 8 Jun 2020 16:59:34 +0200 Subject: [PATCH 10/12] Improved IterIndex naming --- src/iter_index.rs | 36 ++++++++++++++++++------------------ src/lib.rs | 4 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/iter_index.rs b/src/iter_index.rs index 8128ea172..e47f45f31 100644 --- a/src/iter_index.rs +++ b/src/iter_index.rs @@ -18,7 +18,7 @@ mod private_iter_index { /// Used by the ``range`` function to know which iterator /// to turn different ranges into. -pub trait IterIndex : private_iter_index::Sealed { +pub trait IteratorIndex : private_iter_index::Sealed { /// The type that [`get`] or [`Itertools::get`] /// returns when called with this type of index. type Output; @@ -27,26 +27,26 @@ pub trait IterIndex : private_iter_index::Sealed { /// /// Prefer calling [`get`] or [`Itertools::get`] instead /// of calling this directly. - fn get(self, from: T) -> Self::Output; + fn index(self, from: T) -> Self::Output; } -impl IterIndex for Range +impl IteratorIndex for Range where I: Iterator { type Output = Take>; - fn get(self, iter: I) -> Self::Output { + fn index(self, iter: I) -> Self::Output { iter.skip(self.start) .take(self.end.saturating_sub(self.start)) } } -impl IterIndex for RangeInclusive +impl IteratorIndex for RangeInclusive where I: Iterator { type Output = Take>; - fn get(self, iter: I) -> Self::Output { + fn index(self, iter: I) -> Self::Output { iter.skip(*self.start()) .take( (1 + *self.end()) @@ -55,52 +55,52 @@ impl IterIndex for RangeInclusive } } -impl IterIndex for RangeTo +impl IteratorIndex for RangeTo where I: Iterator { type Output = Take; - fn get(self, iter: I) -> Self::Output { + fn index(self, iter: I) -> Self::Output { iter.take(self.end) } } -impl IterIndex for RangeToInclusive +impl IteratorIndex for RangeToInclusive where I: Iterator { type Output = Take; - fn get(self, iter: I) -> Self::Output { + fn index(self, iter: I) -> Self::Output { iter.take(self.end + 1) } } -impl IterIndex for RangeFrom +impl IteratorIndex for RangeFrom where I: Iterator { type Output = Skip; - fn get(self, iter: I) -> Self::Output { + fn index(self, iter: I) -> Self::Output { iter.skip(self.start) } } -impl IterIndex for RangeFull +impl IteratorIndex for RangeFull where I: Iterator { type Output = I; - fn get(self, iter: I) -> Self::Output { + fn index(self, iter: I) -> Self::Output { iter } } -impl IterIndex for usize +impl IteratorIndex for usize where I: Iterator { type Output = Option; - fn get(self, mut iter: I) -> Self::Output { + fn index(self, mut iter: I) -> Self::Output { iter.nth(self) } } @@ -112,7 +112,7 @@ impl IterIndex for usize pub fn get(iter: I, index: R) -> R::Output where I: IntoIterator, - R: IterIndex + R: IteratorIndex { - index.get(iter.into_iter()) + index.index(iter.into_iter()) } diff --git a/src/lib.rs b/src/lib.rs index e7e4c06be..439007910 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,7 +143,7 @@ pub mod structs { /// Traits helpful for using certain `Itertools` methods in generic contexts. pub mod traits { pub use crate::tuple_impl::HomogeneousTuple; - pub use crate::iter_index::IterIndex; + pub use crate::iter_index::IteratorIndex; } #[allow(deprecated)] @@ -440,7 +440,7 @@ pub trait Itertools : Iterator { /// [`nth`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.nth fn get(self, index: R) -> R::Output - where R: iter_index::IterIndex, + where R: iter_index::IteratorIndex, Self: Sized { iter_index::get(self, index) From 2ebe2bde4f7a94809bd4e81c889489e26dad662f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Mon, 8 Jun 2020 18:01:45 +0200 Subject: [PATCH 11/12] get handles generics a little better --- src/iter_index.rs | 12 +++++++----- src/lib.rs | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/iter_index.rs b/src/iter_index.rs index e47f45f31..aede47e0f 100644 --- a/src/iter_index.rs +++ b/src/iter_index.rs @@ -18,16 +18,18 @@ mod private_iter_index { /// Used by the ``range`` function to know which iterator /// to turn different ranges into. -pub trait IteratorIndex : private_iter_index::Sealed { +pub trait IteratorIndex : private_iter_index::Sealed + where I: Iterator +{ /// The type that [`get`] or [`Itertools::get`] /// returns when called with this type of index. - type Output; + type Output: Iterator; /// Returns an iterator(or value) in the specified range. /// /// Prefer calling [`get`] or [`Itertools::get`] instead /// of calling this directly. - fn index(self, from: T) -> Self::Output; + fn index(self, from: I) -> Self::Output; } impl IteratorIndex for Range @@ -98,10 +100,10 @@ impl IteratorIndex for RangeFull impl IteratorIndex for usize where I: Iterator { - type Output = Option; + type Output = as IntoIterator>::IntoIter; fn index(self, mut iter: I) -> Self::Output { - iter.nth(self) + iter.nth(self).into_iter() } } diff --git a/src/lib.rs b/src/lib.rs index 439007910..76b144803 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -431,8 +431,8 @@ pub trait Itertools : Iterator { /// range = vec.iter().get(..).copied().collect(); /// assert_eq!(range, vec); /// - /// let value = vec.iter().get(3).copied(); - /// assert_eq!(value, Some(1)); + /// range = vec.iter().get(3).copied().collect(); + /// assert_eq!(&range, &[1]); /// ``` /// /// [`take`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take From d4339b8795ac388cb9c162bc3ea739e08ea7c5d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20H=C3=B6rnvall?= Date: Sun, 8 May 2022 22:48:41 +0200 Subject: [PATCH 12/12] Included suggestions and formatted --- src/iter_index.rs | 12 +----------- src/lib.rs | 9 ++++----- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/iter_index.rs b/src/iter_index.rs index aede47e0f..f92c818a0 100644 --- a/src/iter_index.rs +++ b/src/iter_index.rs @@ -13,7 +13,6 @@ mod private_iter_index { impl Sealed for ops::RangeToInclusive {} impl Sealed for ops::RangeFrom {} impl Sealed for ops::RangeFull {} - impl Sealed for usize {} } /// Used by the ``range`` function to know which iterator @@ -49,6 +48,7 @@ impl IteratorIndex for RangeInclusive type Output = Take>; fn index(self, iter: I) -> Self::Output { + debug_assert!(!self.is_empty(), "The given `RangeInclusive` is exhausted. The result of indexing with an exhausted `RangeInclusive` is unspecified."); iter.skip(*self.start()) .take( (1 + *self.end()) @@ -97,16 +97,6 @@ impl IteratorIndex for RangeFull } } -impl IteratorIndex for usize - where I: Iterator -{ - type Output = as IntoIterator>::IntoIter; - - fn index(self, mut iter: I) -> Self::Output { - iter.nth(self).into_iter() - } -} - /// Returns an element of the iterator or an iterator /// over a subsection of the iterator. /// diff --git a/src/lib.rs b/src/lib.rs index e5b191c85..60b2aa451 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -519,16 +519,15 @@ pub trait Itertools : Iterator { /// /// range = vec.iter().get(..).copied().collect(); /// assert_eq!(range, vec); - /// - /// range = vec.iter().get(3).copied().collect(); - /// assert_eq!(&range, &[1]); /// ``` /// + /// # Unspecified Behavior + /// The result of indexing with an exhausted [`core::ops::RangeInclusive`] is unspecified. + /// /// [`take`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take /// [`skip`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.skip /// [`nth`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.nth - fn get(self, index: R) - -> R::Output + fn get(self, index: R) -> R::Output where R: iter_index::IteratorIndex, Self: Sized {