iter_identify_first_last/
lib.rs

1#![cfg_attr(feature="nightly", feature(trusted_len))]
2
3#![deny(warnings)]
4#![doc(test(attr(deny(warnings))))]
5#![doc(test(attr(allow(dead_code))))]
6#![doc(test(attr(allow(unused_variables))))]
7#![allow(clippy::needless_doctest_main)]
8#![allow(clippy::type_complexity)]
9
10//! ## Feature flags
11#![doc=document_features::document_features!()]
12
13#![no_std]
14
15#[doc=include_str!("../README.md")]
16type _DocTestReadme = ();
17
18use core::fmt::{self, Debug, Formatter};
19use core::iter::{FusedIterator, Map, Peekable};
20#[cfg(feature="nightly")]
21use core::iter::TrustedLen;
22use core::mem::replace;
23
24/// An iterator that yields the marking the boundary elements boolean flags and the element during iteration.
25///
26/// This struct is created by the [`identify_first_last`](IteratorIdentifyFirstLastExt::identify_first_last)
27/// extension method on [`Iterator`]. See its documentation for more.
28pub struct IdentifyFirstLast<I: Iterator>(
29    Map<IdentifyFirst<IdentifyLast<I>>, fn((bool, (bool, I::Item))) -> (bool, bool, I::Item)>
30);
31
32impl<I: Iterator + Debug> Debug for IdentifyFirstLast<I> where I::Item: Debug {
33    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { self.0.fmt(f) }
34}
35
36impl<I: Iterator + Clone> Clone for IdentifyFirstLast<I> where I::Item: Clone {
37    fn clone(&self) -> Self { IdentifyFirstLast(self.0.clone()) }
38}
39
40impl<I: Iterator> Iterator for IdentifyFirstLast<I> {
41    type Item = (bool, bool, I::Item);
42
43    fn next(&mut self) -> Option<Self::Item> { self.0.next() }
44
45    fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
46}
47
48#[cfg(feature="nightly")]
49unsafe impl<I: TrustedLen> TrustedLen for IdentifyFirstLast<I> { }
50
51impl<I: ExactSizeIterator> ExactSizeIterator for IdentifyFirstLast<I> {
52    fn len(&self) -> usize { self.0.len() }
53}
54
55impl<I: FusedIterator> FusedIterator for IdentifyFirstLast<I> { }
56
57/// An iterator that yields the marking the last element boolean flag and the element during iteration.
58///
59/// This struct is created by the [`identify_last`](IteratorIdentifyFirstLastExt::identify_last)
60/// extension method on [`Iterator`]. See its documentation for more.
61pub struct IdentifyLast<I: Iterator> {
62    iter: Peekable<I>,
63}
64
65impl<I: Iterator + Debug> Debug for IdentifyLast<I> where I::Item: Debug {
66    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { self.iter.fmt(f) }
67}
68
69impl<I: Iterator + Clone> Clone for IdentifyLast<I> where I::Item: Clone {
70    fn clone(&self) -> Self { IdentifyLast { iter: self.iter.clone() } }
71}
72
73impl<I: Iterator> Iterator for IdentifyLast<I> {
74    type Item = (bool, I::Item);
75
76    fn next(&mut self) -> Option<Self::Item> {
77        if let Some(item) = self.iter.next() {
78            let is_last = self.iter.peek().is_none();
79            Some((is_last, item))
80        } else {
81            None
82        }
83    }
84
85    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
86}
87
88#[cfg(feature="nightly")]
89unsafe impl<I: TrustedLen> TrustedLen for IdentifyLast<I> { }
90
91impl<I: ExactSizeIterator> ExactSizeIterator for IdentifyLast<I> {
92    fn len(&self) -> usize { self.iter.len() }
93}
94
95/// An iterator that yields the marking the first element boolean flag and the element during iteration.
96///
97/// This struct is created by the [`identify_first`](IteratorIdentifyFirstLastExt::identify_first)
98/// extension method on [`Iterator`]. See its documentation for more.
99#[derive(Debug, Clone)]
100pub struct IdentifyFirst<I: Iterator> {
101    is_first: bool,
102    iter: I,
103}
104
105impl<I: Iterator> Iterator for IdentifyFirst<I> {
106    type Item = (bool, I::Item);
107
108    fn next(&mut self) -> Option<Self::Item> {
109        if let Some(item) = self.iter.next() {
110            let is_first = replace(&mut self.is_first, false);
111            Some((is_first, item))
112        } else {
113            self.is_first = true;
114            None
115        }
116    }
117
118    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
119}
120
121#[cfg(feature="nightly")]
122unsafe impl<I: TrustedLen> TrustedLen for IdentifyFirst<I> { }
123
124impl<I: ExactSizeIterator> ExactSizeIterator for IdentifyFirst<I> {
125    fn len(&self) -> usize { self.iter.len() }
126}
127
128impl<I: FusedIterator> FusedIterator for IdentifyFirst<I> { }
129
130/// Extends [`Iterator`] with methods for marking first and last elements with boolean flags.
131pub trait IteratorIdentifyFirstLastExt: Iterator + Sized {
132    /// Creates an iterator which gives the `is_first` flag as well as the next value.
133    ///
134    /// The iterator returned yields pairs `(is_first, val)`,
135    /// where `is_first` is the boolean which is true for the first element and false for the others,
136    /// and `val` is the value returned by the iterator.
137    fn identify_first(self) -> IdentifyFirst<Self>;
138
139    /// Creates an iterator which gives the `is_last` flag as well as the next value.
140    ///
141    /// The iterator returned yields pairs `(is_last, val)`,
142    /// where `is_last` is the boolean which is true for the last element and false for the others,
143    /// and `val` is the value returned by the iterator.
144    fn identify_last(self) -> IdentifyLast<Self>;
145
146    /// Creates an iterator which gives the `is_first` and `is_last` flags as well as the next value.
147    ///
148    /// The iterator returned yields triples `(is_first, is_last, val)`,
149    /// where `is_first` is the boolean which is true for the first element and false for the others,
150    /// `is_last` is the boolean which is true for the last element and false for the others,
151    /// and `val` is the value returned by the iterator.
152    fn identify_first_last(self) -> IdentifyFirstLast<Self>;
153}
154
155impl<I: Iterator + Sized> IteratorIdentifyFirstLastExt for I {
156    fn identify_first(self) -> IdentifyFirst<Self> { IdentifyFirst { is_first: true, iter: self } }
157
158    fn identify_last(self) -> IdentifyLast<Self> { IdentifyLast { iter: self.peekable() } }
159
160    fn identify_first_last(self) -> IdentifyFirstLast<Self> {
161        IdentifyFirstLast(self.identify_last().identify_first().map(
162            |(is_first, (is_last, item))| (is_first, is_last, item)
163        ))
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use arrayvec::ArrayVec;
170    use crate::IteratorIdentifyFirstLastExt;
171
172    #[test]
173    fn identify_first() {
174        assert_eq!(
175            [1, 2, 3, 4].into_iter().identify_first().collect::<ArrayVec<_, 4>>().as_slice(),
176            &[(true, 1), (false, 2), (false, 3), (false, 4)]
177        );
178    }
179
180    #[test]
181    fn identify_last() {
182        assert_eq!(
183            [1, 2, 3, 4].into_iter().identify_last().collect::<ArrayVec<_, 4>>().as_slice(),
184            &[(false, 1), (false, 2), (false, 3), (true, 4)]
185        );
186    }
187
188    #[test]
189    fn identify_first_last() {
190        assert_eq!(
191            [1, 2, 3, 4].into_iter().identify_first_last().collect::<ArrayVec<_, 4>>().as_slice(),
192            &[(true, false, 1), (false, false, 2), (false, false, 3), (false, true, 4)]
193        );
194    }
195}