discard_while/
lib.rs

1#![no_std]
2//! Iterator utility for getting the first non-matching element,
3//! discarding any others, and the amount of discarded elements.
4//!
5//! To use, either `use discard_while::discard_while` to get the function,
6//! or `use discard_while::DiscardWhile` to get the convenience trait.
7
8/// Advance an iterator as long as a condition on the yielded items holds.
9/// Returns the first item that no longer satisfies the condition, if any,
10/// and the number of items discarded.
11///
12/// This is similar to a combination of [`find`] and [`position`].
13///
14/// _Note_: This function takes any implementation of [`IntoIterator`], which includes
15/// iterators themselves and mutable references to them.
16///
17/// # Overflow Behavior
18///
19/// The method does no guarding against overflows, so if there are more than `usize::MAX`
20/// non-matching elements, it either produces the wrong result or panics.
21/// If overflow checks are enabled, a panic is guaranteed.
22///
23/// # Panics
24///
25/// This function might panic if the iterator has more than `usize::MAX` non-matching elements.
26///
27/// # Examples
28///
29/// Basic usage:
30///
31/// ```
32/// # use discard_while::discard_while;
33/// let mut range = 1..=10;
34/// let result = discard_while(&mut range, |&n| n != 5);
35/// assert_eq!(result, (Some(5), 4));
36/// assert_eq!(range, 6..=10);
37/// ```
38///
39/// If the iterator ends before an item that does not fulfill the condition
40/// is encountered, [`None`] is returned as the first return value.
41///
42/// ```
43/// # use discard_while::discard_while;
44/// let arr = [6, 5, 4, 3, 2, 1];
45/// let result = discard_while(arr, |&n| true);
46/// assert_eq!(result, (None, 6));
47/// ```
48///
49/// If the first element that is encountered does not fulfill the condition,
50/// `0` is returned as the second return value.
51///
52/// ```
53/// # use discard_while::discard_while;
54/// let mut range = 2..=8;
55/// let result = discard_while(&mut range, |&n| false);
56/// assert_eq!(result, (Some(2), 0));
57/// assert_eq!(range, 3..=8);
58/// ```
59///
60/// [`find`]: Iterator::find
61/// [`position`]: Iterator::position
62pub fn discard_while<T>(
63    iter: impl IntoIterator<Item = T>,
64    mut cond: impl FnMut(&T) -> bool,
65) -> (Option<T>, usize) {
66    let iter = iter.into_iter();
67    let mut i = 0;
68    for next in iter {
69        if !cond(&next) {
70            return (Some(next), i);
71        }
72        i += 1;
73    }
74    (None, i)
75}
76
77/// Convenience trait to allow using [`discard_while`] as a method.
78/// This trait is implemented for every [`Iterator`].
79pub trait DiscardWhile: Iterator {
80    /// Advance the iterator as long as a condition on the yielded items holds.
81    /// Returns the first item that no longer satisfies the condition, if any,
82    /// and the number of items discarded.
83    ///
84    /// This is similar to a combination of [`find`] and [`position`].
85    ///
86    /// # Overflow Behavior
87    ///
88    /// The method does no guarding against overflows, so if there are more than `usize::MAX`
89    /// non-matching elements, it either produces the wrong result or panics.
90    /// If overflow checks are enabled, a panic is guaranteed.
91    ///
92    /// # Panics
93    ///
94    /// This function might panic if the iterator has more than `usize::MAX` non-matching elements.
95    ///
96    /// # Examples
97    ///
98    /// Basic usage:
99    ///
100    /// ```
101    /// # use discard_while::DiscardWhile;
102    /// let mut range = 1..=10;
103    /// let result = range.discard_while(|&n| n != 5);
104    /// assert_eq!(result, (Some(5), 4));
105    /// assert_eq!(range, 6..=10);
106    /// ```
107    ///
108    /// If the iterator ends before an item that does not fulfill the condition
109    /// is encountered, [`None`] is returned as the first return value.
110    ///
111    /// ```
112    /// # use discard_while::DiscardWhile;
113    /// let mut range = 1..=10;
114    /// let result = range.discard_while(|&n| true);
115    /// assert_eq!(result, (None, 10));
116    /// assert!(range.is_empty());
117    /// ```
118    /// If the first element that is encountered does not fulfill the condition,
119    /// `0` is returned as the second return value.
120    ///
121    /// ```
122    /// # use discard_while::DiscardWhile;
123    /// let mut range = 1..=10;
124    /// let result = range.discard_while(|&n| false);
125    /// assert_eq!(result, (Some(1), 0));
126    /// assert_eq!(range, 2..=10);
127    /// ```
128    /// [`find`]: Iterator::find
129    /// [`position`]: Iterator::position
130    fn discard_while(
131        &mut self,
132        cond: impl FnMut(&Self::Item) -> bool,
133    ) -> (Option<Self::Item>, usize)
134    where
135        Self: Sized,
136    {
137        discard_while(self, cond)
138    }
139}
140
141impl<T: Iterator> DiscardWhile for T {}