From 6d39221478078979ba883e7abd0ad6fd83d11e18 Mon Sep 17 00:00:00 2001 From: herlev <> Date: Mon, 21 Aug 2023 15:09:19 +0200 Subject: [PATCH 1/4] add next_if and next_if_eq to PeekNth, such that it matches the functionality found in std::iter::Peekable --- src/peek_nth.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/peek_nth.rs b/src/peek_nth.rs index 1ae428ba0..fcdff384d 100644 --- a/src/peek_nth.rs +++ b/src/peek_nth.rs @@ -115,6 +115,23 @@ where self.buf.get_mut(n) } + + /// Works exactly like the `next_if` method in `std::iter::Peekable` + pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option { + match self.peek() { + Some(m) if func(&m) => self.next(), + _ => None, + } + } + + /// Works exactly like the `next_if_eq` method in `std::iter::Peekable` + pub fn next_if_eq(&mut self, expected: &T) -> Option + where + T: ?Sized, + I::Item: PartialEq, + { + self.next_if(|next| next == expected) + } } impl Iterator for PeekNth From 86f8d4e0bdaa20c5315e54cfc8c1baac4d7f068f Mon Sep 17 00:00:00 2001 From: Philippe-Cholet Date: Tue, 10 Oct 2023 10:03:03 +0200 Subject: [PATCH 2/4] `PeekNth::next_if`: avoid "peek+next" Similarly, `Peekable::next_if` does not "peek" before calling "next" either. --- src/peek_nth.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/peek_nth.rs b/src/peek_nth.rs index fcdff384d..5f7fb9396 100644 --- a/src/peek_nth.rs +++ b/src/peek_nth.rs @@ -118,8 +118,12 @@ where /// Works exactly like the `next_if` method in `std::iter::Peekable` pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option { - match self.peek() { - Some(m) if func(&m) => self.next(), + match self.next() { + Some(item) if func(&item) => Some(item), + Some(item) => { + self.buf.push_front(item); + None + } _ => None, } } From e29603778e90d27bb836a29144b0554953b7f5dd Mon Sep 17 00:00:00 2001 From: Philippe-Cholet Date: Tue, 10 Oct 2023 10:58:36 +0200 Subject: [PATCH 3/4] `test_peek_nth_next_if` Same as `test_peek_nth_peeking_next` (copied/pasted/updated) but with `next_if[_eq]` instead of using `peeking_next` from our `itertools::PeekingNext` trait. --- tests/test_std.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/test_std.rs b/tests/test_std.rs index 3ef90f39d..732790ef4 100644 --- a/tests/test_std.rs +++ b/tests/test_std.rs @@ -738,6 +738,35 @@ fn test_peek_nth_peeking_next() { assert_eq!(iter.peek(), None); } +#[test] +fn test_peek_nth_next_if() { + let nums = vec![1u8, 2, 3, 4, 5, 6, 7]; + let mut iter = peek_nth(nums.iter().copied()); + + assert_eq!(iter.next_if(|&x| x != 0), Some(1)); + assert_eq!(iter.next(), Some(2)); + + assert_eq!(iter.peek_nth(0), Some(&3)); + assert_eq!(iter.peek_nth(1), Some(&4)); + assert_eq!(iter.next_if_eq(&3), Some(3)); + assert_eq!(iter.peek(), Some(&4)); + + assert_eq!(iter.next_if(|&x| x != 4), None); + assert_eq!(iter.next_if_eq(&4), Some(4)); + assert_eq!(iter.peek_nth(0), Some(&5)); + assert_eq!(iter.peek_nth(1), Some(&6)); + + assert_eq!(iter.next_if(|&x| x != 5), None); + assert_eq!(iter.peek(), Some(&5)); + + assert_eq!(iter.next_if(|&x| x % 2 == 1), Some(5)); + assert_eq!(iter.next_if_eq(&6), Some(6)); + assert_eq!(iter.peek_nth(0), Some(&7)); + assert_eq!(iter.peek_nth(1), None); + assert_eq!(iter.next(), Some(7)); + assert_eq!(iter.peek(), None); +} + #[test] fn pad_using() { it::assert_equal((0..0).pad_using(1, |_| 1), 1..2); From 50f1cd0daf72458016cedba22c9248212ad77c85 Mon Sep 17 00:00:00 2001 From: Philippe-Cholet Date: Tue, 10 Oct 2023 11:38:25 +0200 Subject: [PATCH 4/4] Add `peek_nth_next_if` quickcheck test --- tests/quick.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/quick.rs b/tests/quick.rs index 0d7cd9307..f0c8f2d9e 100644 --- a/tests/quick.rs +++ b/tests/quick.rs @@ -782,6 +782,30 @@ quickcheck! { assert_eq!(it.next(), None); assert_eq!(it.next(), None); } + + fn peek_nth_next_if(a: Vec) -> () { + let mut it = peek_nth(a.clone()); + for (idx, mut value) in a.iter().copied().enumerate() { + let should_be_none = it.next_if(|x| x != &value); + assert_eq!(should_be_none, None); + if value % 5 == 0 { + // Sometimes, peek up to 3 further. + let n = value as usize % 3; + let nth = it.peek_nth(n); + assert_eq!(nth, a.get(idx + n)); + } else if value % 5 == 1 { + // Sometimes, peek next element mutably. + if let Some(v) = it.peek_mut() { + *v = v.wrapping_sub(1); + let should_be_none = it.next_if_eq(&value); + assert_eq!(should_be_none, None); + value = value.wrapping_sub(1); + } + } + let eq = it.next_if_eq(&value); + assert_eq!(eq, Some(value)); + } + } } quickcheck! {