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 {}