double_ended_peekable/lib.rs
1//! A peekable abstraction for double-ended iterators.
2//!
3//! This crate provides an _extension trait_ to standard [`Iterator`] in order to lift the
4//! [`Peekable`] abstraction over types implementing [`DoubleEndedIterator`].
5//!
6//! # Basic usage
7//!
8//! ```
9//! use double_ended_peekable::DoubleEndedPeekableExt;
10//!
11//! // Now you can use `iter.double_ended_peekable()`
12//! let mut iter = [1, 2, 3, 4].into_iter().double_ended_peekable();
13//! // Same abstractions of `Peekable`
14//! assert_eq!(iter.peek(), Some(&1));
15//! // Additional `*_back*` methods
16//! assert_eq!(iter.peek_back(), Some(&4));
17//! // It implements `Iterator`
18//! assert_eq!(iter.next(), Some(1));
19//! // And also `DoubleEndedIterator` when possible
20//! assert_eq!(iter.next_back(), Some(4));
21//! // Additional methods for both front and back items
22//! assert_eq!(iter.next_front_back_if_eq(&2, &3), Some((2, 3)));
23//! ```
24//!
25//! Check [`DoubleEndedPeekable`] documentation for additional information.
26//!
27//! # Rationale
28//!
29//! It is possible to use [`Peekable`] on double-ended iterators using `.rev().peekable()`:
30//!
31//! ```
32//! let mut iter = [1, 2, 3].into_iter().rev().peekable();
33//! // No problem!
34//! assert_eq!(iter.peek(), Some(&3));
35//! ````
36//!
37//! However, using `.by_ref().rev().peekable()` _on the fly_ is a footgun:
38//! ```should_panic
39//! let mut iter = [1, 2, 3, 4].into_iter().peekable();
40//! assert_eq!(iter.peek(), Some(&1));
41//! assert_eq!(iter.by_ref().rev().peekable().peek(), Some(&4));
42//! assert_eq!(iter.next(), Some(1));
43//!
44//! // Dang! This fails: iter.next_back() == Some(3)
45//! assert_eq!(iter.next_back(), Some(4));
46//! ```
47//!
48//! The assertion fails just because [`Peekable`] saves the next item of the iterator internally.
49//! Therefore, creating a _rev-peekable_ iterator on the fly is risky because there is a good
50//! chance a peeked element is going to be accidentally lost.
51//!
52//! This tiny crate exposes a simple but powerful abstraction that is hard to misuse.
53//!
54//! [`Peekable`]: core::iter::Peekable
55
56#![cfg_attr(not(test), no_std)]
57
58#[cfg(test)]
59mod tests;
60
61use core::{
62 fmt::{self, Debug},
63 hash::{Hash, Hasher},
64 hint::unreachable_unchecked,
65 mem,
66};
67
68/// An _extension trait_ to create [`DoubleEndedPeekable`].
69///
70/// This has a blanket implementation for all types that implement [`Iterator`].
71pub trait DoubleEndedPeekableExt<I: Iterator> {
72 /// Creates an iterator which works similarly to [`Peekable`], but also provides additional
73 /// functions if the underlying type implements [`DoubleEndedIterator`].
74 ///
75 /// See [`DoubleEndedPeekable`] for more information.
76 ///
77 /// [`Peekable`]: core::iter::Peekable
78 fn double_ended_peekable(self) -> DoubleEndedPeekable<I>;
79}
80
81impl<I> DoubleEndedPeekableExt<I> for I
82where
83 I: Iterator,
84{
85 #[inline]
86 fn double_ended_peekable(self) -> DoubleEndedPeekable<I> {
87 DoubleEndedPeekable {
88 iter: self,
89 front: MaybePeeked::Unpeeked,
90 back: MaybePeeked::Unpeeked,
91 }
92 }
93}
94
95/// An advanced version of [`Peekable`] that works well with double-ended iterators.
96///
97/// This `struct` is created by the [`double_ended_peekable`] method on [`DoubleEndedPeekableExt`].
98///
99/// [`Peekable`]: core::iter::Peekable
100/// [`double_ended_peekable`]: DoubleEndedPeekableExt::double_ended_peekable
101pub struct DoubleEndedPeekable<I: Iterator> {
102 iter: I,
103 front: MaybePeeked<<I as Iterator>::Item>,
104 back: MaybePeeked<<I as Iterator>::Item>,
105}
106
107impl<I: Iterator> DoubleEndedPeekable<I> {
108 /// Returns a reference to the `next()` value without advancing the iterator.
109 ///
110 /// See [`Peekable::peek`] for more information.
111 ///
112 /// [`Peekable::peek`]: core::iter::Peekable::peek
113 #[inline]
114 pub fn peek(&mut self) -> Option<&I::Item> {
115 self.front
116 .get_peeked_or_insert_with(|| self.iter.next())
117 .as_ref()
118 .or_else(|| self.back.peeked_value_ref())
119 }
120
121 /// Returns a mutable reference to the `next()` value without advancing the iterator.
122 ///
123 /// See [`Peekable::peek_mut`] for more information.
124 ///
125 /// [`Peekable::peek_mut`]: core::iter::Peekable::peek_mut
126 #[inline]
127 pub fn peek_mut(&mut self) -> Option<&mut I::Item> {
128 self.front
129 .get_peeked_or_insert_with(|| self.iter.next())
130 .as_mut()
131 .or_else(|| self.back.peeked_value_mut())
132 }
133
134 /// Consumes and returns the next value of this iterator if a condition is true.
135 ///
136 /// See [`Peekable::next_if`] for more information.
137 ///
138 /// [`Peekable::next_if`]: core::iter::Peekable::next_if
139 #[inline]
140 pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
141 match self.next() {
142 Some(item) if func(&item) => Some(item),
143 other => {
144 debug_assert!(self.front.is_unpeeked());
145 self.front = MaybePeeked::Peeked(other);
146 None
147 }
148 }
149 }
150
151 /// Consumes and returns the next item if it is equal to `expected`.
152 ///
153 /// See [`Peekable::next_if_eq`] for more information.
154 ///
155 /// [`Peekable::next_if_eq`]: core::iter::Peekable::next_if
156 #[inline]
157 pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
158 where
159 T: ?Sized,
160 I::Item: PartialEq<T>,
161 {
162 self.next_if(|item| item == expected)
163 }
164}
165
166impl<I: DoubleEndedIterator> DoubleEndedPeekable<I> {
167 /// Returns a reference to the `next_back()` value without advancing the _back_ of the iterator.
168 ///
169 /// Like [`next_back`], if there is a value, it is wrapped in a `Some(T)`.
170 /// But if the iteration is over, `None` is returned.
171 ///
172 /// [`next_back`]: DoubleEndedIterator::next_back
173 ///
174 /// Because `peek_back()` returns a reference, and many iterators iterate over references,
175 /// there can be a possibly confusing situation where the return value is a double reference.
176 /// You can see this effect in the examples below.
177 ///
178 /// # Examples
179 ///
180 /// Basic usage:
181 ///
182 /// ```
183 /// use double_ended_peekable::DoubleEndedPeekableExt;
184 ///
185 /// let xs = [1, 2, 3];
186 ///
187 /// let mut iter = xs.into_iter().double_ended_peekable();
188 ///
189 /// // peek_back() lets us see into the past of the future
190 /// assert_eq!(iter.peek_back(), Some(&3));
191 /// assert_eq!(iter.next_back(), Some(3));
192 ///
193 /// assert_eq!(iter.next_back(), Some(2));
194 ///
195 /// // The iterator does not advance even if we `peek_back` multiple times
196 /// assert_eq!(iter.peek_back(), Some(&1));
197 /// assert_eq!(iter.peek_back(), Some(&1));
198 ///
199 /// assert_eq!(iter.next_back(), Some(1));
200 ///
201 /// // After the iterator is finished, so is `peek_back()`
202 /// assert_eq!(iter.peek_back(), None);
203 /// assert_eq!(iter.next_back(), None);
204 /// ```
205 #[inline]
206 pub fn peek_back(&mut self) -> Option<&I::Item> {
207 self.back
208 .get_peeked_or_insert_with(|| self.iter.next_back())
209 .as_ref()
210 .or_else(|| self.front.peeked_value_ref())
211 }
212
213 /// Returns a mutable reference to the `next_back()` value without advancing the _back_ of the
214 /// iterator.
215 ///
216 /// Like [`next_back`], if there is a value, it is wrapped in a `Some(T)`. But if the iteration
217 /// is over, `None` is returned.
218 ///
219 /// Because `peek_back_mut()` returns a reference, and many iterators iterate over references,
220 /// there can be a possibly confusing situation where the return value is a double reference.
221 /// You can see this effect in the examples below.
222 ///
223 /// [`next_back`]: DoubleEndedIterator::next_back
224 ///
225 /// # Examples
226 ///
227 /// Basic usage:
228 ///
229 /// ```
230 /// use double_ended_peekable::DoubleEndedPeekableExt;
231 ///
232 /// let mut iter = [1, 2, 3].into_iter().double_ended_peekable();
233 ///
234 /// // Like with `peek_back()`, we can see into the past of the future without advancing the
235 /// // iterator.
236 /// assert_eq!(iter.peek_back_mut(), Some(&mut 3));
237 /// assert_eq!(iter.peek_back_mut(), Some(&mut 3));
238 /// assert_eq!(iter.next_back(), Some(3));
239 ///
240 /// // Peek into the _back_ of the iterator and set the value behind the mutable reference.
241 /// if let Some(p) = iter.peek_back_mut() {
242 /// assert_eq!(*p, 2);
243 /// *p = 5;
244 /// }
245 ///
246 /// // The value we put in reappears as the iterator continues.
247 /// assert_eq!(iter.collect::<Vec<_>>(), vec![1, 5]);
248 /// ```
249 #[inline]
250 pub fn peek_back_mut(&mut self) -> Option<&mut I::Item> {
251 self.back
252 .get_peeked_or_insert_with(|| self.iter.next_back())
253 .as_mut()
254 .or_else(|| self.front.peeked_value_mut())
255 }
256
257 /// Consumes and returns the _next back_ value of this iterator if a condition is true.
258 ///
259 /// If `func` returns `true` for the _next back_ value of this iterator, it consumes the
260 /// element and returns it. Otherwise, it returns `None`.
261 ///
262 /// # Examples
263 /// Consume a number if it's equal to 4.
264 /// ```
265 /// use double_ended_peekable::DoubleEndedPeekableExt;
266 ///
267 /// let mut iter = (0..5).double_ended_peekable();
268 /// // The last item of the iterator is 4; consume it.
269 /// assert_eq!(iter.next_back_if(|&x| x == 4), Some(4));
270 /// // The _next back_ item returned is now 3, so `consume` will return `false`.
271 /// assert_eq!(iter.next_back_if(|&x| x == 4), None);
272 /// // `next_back_if` saves the value of the _next back_ item if it was not equal to
273 /// // `expected`.
274 /// assert_eq!(iter.next_back(), Some(3));
275 /// ```
276 ///
277 /// Consume any number greater than 10.
278 /// ```
279 /// use double_ended_peekable::DoubleEndedPeekableExt;
280 ///
281 /// let mut iter = (1..20).double_ended_peekable();
282 /// // Consume all numbers greater than 10
283 /// while iter.next_back_if(|&x| x > 10).is_some() {}
284 /// // The _next _back_ value returned will be 10
285 /// assert_eq!(iter.next_back(), Some(10));
286 /// ```
287 #[inline]
288 pub fn next_back_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
289 match self.next_back() {
290 Some(item) if func(&item) => Some(item),
291 other => {
292 debug_assert!(self.back.is_unpeeked());
293 self.back = MaybePeeked::Peeked(other);
294 None
295 }
296 }
297 }
298
299 /// Consumes and returns the _next back_ item if it is equal to `expected`.
300 ///
301 /// # Example
302 /// Consume a number if it's equal to 4.
303 /// ```
304 /// use double_ended_peekable::DoubleEndedPeekableExt;
305 ///
306 /// let mut iter = (0..5).double_ended_peekable();
307 /// // The first item of the iterator is 4; consume it.
308 /// assert_eq!(iter.next_back_if_eq(&4), Some(4));
309 /// // The next item returned is now 3, so `consume` will return `false`.
310 /// assert_eq!(iter.next_back_if_eq(&4), None);
311 /// // `next_if_eq` saves the value of the _next back_ item if it was not equal to `expected`.
312 /// assert_eq!(iter.next_back(), Some(3));
313 /// ```
314 #[inline]
315 pub fn next_back_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
316 where
317 T: ?Sized,
318 I::Item: PartialEq<T>,
319 {
320 self.next_back_if(|item| item == expected)
321 }
322
323 /// Consumes and returns the _front_ and _back_ elements of this iterator if a condition is true.
324 ///
325 /// If `func` returns `true` given the references to the _front_ and _back_ elements of this
326 /// iterator, it consumes the elements and returns them. Otherwise, it returns `None`.
327 ///
328 /// If there is only one element left, it returns `None`;
329 ///
330 /// # Examples
331 /// Consume a pair of numbers if the first is 0 and the second is 4.
332 /// ```
333 /// use double_ended_peekable::DoubleEndedPeekableExt;
334 ///
335 /// let mut iter = (0..5).double_ended_peekable();
336 /// // The first item of the iterator is 0 and the last is 4; consume it.
337 /// assert_eq!(iter.next_front_back_if(|&a, &b| a == 0 && b == 4), Some((0, 4)));
338 /// // The pair returned is now `(1, 3)`, so `consume` will return `false`.
339 /// assert_eq!(iter.next_front_back_if(|&a, &b| a == 0 && b == 4), None);
340 /// // `next_front_back_if` saves the both the _front_ and the _back_ values if the function
341 /// // returned `false`.
342 /// assert_eq!(iter.next(), Some(1));
343 /// assert_eq!(iter.next_back(), Some(3));
344 /// ```
345 ///
346 /// Consume any number greater than 10, in pairs.
347 /// ```
348 /// use double_ended_peekable::DoubleEndedPeekableExt;
349 ///
350 /// let mut iter = [12, 11, 10, 9, 10, 11, 12, 13].into_iter().double_ended_peekable();
351 /// // Consume all numbers greater than 10, in pairs
352 /// while iter.next_front_back_if(|&a, &b| a > 10 && b > 10).is_some() {}
353 /// // The remaining elements
354 /// assert_eq!(iter.collect::<Vec<_>>(), [10, 9, 10, 11]);
355 /// ```
356 #[inline]
357 pub fn next_front_back_if(
358 &mut self,
359 func: impl FnOnce(&I::Item, &I::Item) -> bool,
360 ) -> Option<(I::Item, I::Item)> {
361 match (self.next(), self.next_back()) {
362 (Some(front), Some(back)) if func(&front, &back) => Some((front, back)),
363 (front, back) => {
364 debug_assert!(self.front.is_unpeeked());
365 debug_assert!(self.back.is_unpeeked());
366 self.front = MaybePeeked::Peeked(front);
367 self.back = MaybePeeked::Peeked(back);
368 None
369 }
370 }
371 }
372
373 /// Consumes and returns the _front_ and _back_ elements of this iterator if they are equal to
374 /// the expected values.
375 ///
376 /// # Example
377 /// Consume any number if they are 10 and 15, respectively.
378 /// ```
379 /// use double_ended_peekable::DoubleEndedPeekableExt;
380 ///
381 /// let mut iter = [10, 10, 9, 15].into_iter().double_ended_peekable();
382 /// // The first and the last items of the iterator are 10 and 15; consume it.
383 /// while iter.next_front_back_if_eq(&10, &15).is_some() {}
384 /// // The remaining elements
385 /// assert_eq!(iter.collect::<Vec<_>>(), [10, 9]);
386 /// ```
387 #[inline]
388 pub fn next_front_back_if_eq<T>(
389 &mut self,
390 expected_front: &T,
391 expected_back: &T,
392 ) -> Option<(I::Item, I::Item)>
393 where
394 T: ?Sized,
395 I::Item: PartialEq<T>,
396 {
397 self.next_front_back_if(|front, back| front == expected_front && back == expected_back)
398 }
399}
400
401impl<I> Iterator for DoubleEndedPeekable<I>
402where
403 I: Iterator,
404{
405 type Item = I::Item;
406
407 #[inline]
408 fn next(&mut self) -> Option<Self::Item> {
409 match self.front.take() {
410 MaybePeeked::Peeked(out @ Some(_)) => out,
411 MaybePeeked::Peeked(None) => self.back.take().into_peeked_value(),
412 MaybePeeked::Unpeeked => match self.iter.next() {
413 item @ Some(_) => item,
414 None => self.back.take().into_peeked_value(),
415 },
416 }
417 }
418
419 #[inline]
420 fn size_hint(&self) -> (usize, Option<usize>) {
421 let (lower, upper) = self.iter.size_hint();
422 let additional = match (&self.front, &self.back) {
423 (MaybePeeked::Peeked(_), MaybePeeked::Peeked(_)) => 2,
424 (MaybePeeked::Peeked(_), _) | (_, MaybePeeked::Peeked(_)) => 1,
425 (MaybePeeked::Unpeeked, MaybePeeked::Unpeeked) => 0,
426 };
427
428 (lower + additional, upper.map(|upper| upper + additional))
429 }
430}
431
432impl<I> DoubleEndedIterator for DoubleEndedPeekable<I>
433where
434 I: DoubleEndedIterator,
435{
436 #[inline]
437 fn next_back(&mut self) -> Option<Self::Item> {
438 match self.back.take() {
439 MaybePeeked::Peeked(out @ Some(_)) => out,
440 MaybePeeked::Peeked(None) => self.front.take().into_peeked_value(),
441 MaybePeeked::Unpeeked => match self.iter.next_back() {
442 out @ Some(_) => out,
443 None => self.front.take().into_peeked_value(),
444 },
445 }
446 }
447}
448
449impl<I> Debug for DoubleEndedPeekable<I>
450where
451 I: Iterator + Debug,
452 I::Item: Debug,
453{
454 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455 f.debug_struct("DoubleEndedPeekable")
456 .field("iter", &self.iter)
457 .field("front", &self.front)
458 .field("back", &self.back)
459 .finish()
460 }
461}
462
463impl<I> Clone for DoubleEndedPeekable<I>
464where
465 I: Iterator + Clone,
466 I::Item: Clone,
467{
468 #[inline]
469 fn clone(&self) -> Self {
470 Self {
471 iter: self.iter.clone(),
472 front: self.front.clone(),
473 back: self.back.clone(),
474 }
475 }
476}
477
478impl<I> PartialEq for DoubleEndedPeekable<I>
479where
480 I: Iterator + PartialEq,
481 I::Item: PartialEq,
482{
483 #[inline]
484 fn eq(&self, other: &Self) -> bool {
485 self.iter == other.iter && self.front == other.front && self.back == other.back
486 }
487}
488
489impl<I> Eq for DoubleEndedPeekable<I>
490where
491 I: Iterator + Eq,
492 I::Item: Eq,
493{
494}
495
496impl<I> Hash for DoubleEndedPeekable<I>
497where
498 I: Iterator + Hash,
499 I::Item: Hash,
500{
501 #[inline]
502 fn hash<H: Hasher>(&self, state: &mut H) {
503 self.iter.hash(state);
504 self.front.hash(state);
505 self.back.hash(state);
506 }
507}
508
509#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
510enum MaybePeeked<T> {
511 #[default]
512 Unpeeked,
513 Peeked(Option<T>),
514}
515
516impl<T> MaybePeeked<T> {
517 fn get_peeked_or_insert_with<F>(&mut self, f: F) -> &mut Option<T>
518 where
519 F: FnOnce() -> Option<T>,
520 {
521 if let MaybePeeked::Unpeeked = self {
522 *self = MaybePeeked::Peeked(f());
523 }
524
525 let MaybePeeked::Peeked(peeked) = self else {
526 // SAFETY: it cannot be `Unpeeked` because that case has been just replaced with
527 // `Peeked`, and we only have two possible states.
528 unsafe { unreachable_unchecked() }
529 };
530 peeked
531 }
532
533 const fn peeked_value_ref(&self) -> Option<&T> {
534 match self {
535 MaybePeeked::Unpeeked | MaybePeeked::Peeked(None) => None,
536 MaybePeeked::Peeked(Some(peeked)) => Some(peeked),
537 }
538 }
539
540 fn peeked_value_mut(&mut self) -> Option<&mut T> {
541 match self {
542 MaybePeeked::Unpeeked | MaybePeeked::Peeked(None) => None,
543 MaybePeeked::Peeked(Some(peeked)) => Some(peeked),
544 }
545 }
546
547 const fn is_unpeeked(&self) -> bool {
548 matches!(self, MaybePeeked::Unpeeked)
549 }
550
551 fn take(&mut self) -> Self {
552 mem::replace(self, MaybePeeked::Unpeeked)
553 }
554
555 fn into_peeked_value(self) -> Option<T> {
556 match self {
557 MaybePeeked::Unpeeked | MaybePeeked::Peeked(None) => None,
558 MaybePeeked::Peeked(Some(peeked)) => Some(peeked),
559 }
560 }
561}