Skip to main content

head_tail_iter/
lib.rs

1#![no_std]
2#![deny(unsafe_code, missing_docs)]
3#![doc = include_str!("../README.md")]
4
5#[cfg(test)]
6mod tests;
7
8use core::iter::FusedIterator;
9
10/// An iterator that splits a slice into its head and tail.
11/// Then, the tail into *its* head and tail, and so on.
12///
13/// Iterator's element type is thus `(&'a T, &'a [T])`.
14///
15/// To construct the iterator, use [`HeadTailIterator::head_tail_pairs()`].
16///
17/// # Example
18///
19/// ```rust
20/// # use std::fmt::Write;
21/// use head_tail_iter::HeadTailIterator;
22///
23/// let mut s = String::new();
24/// for x in [0, 1, 2, 3].head_tail_pairs() {
25///     writeln!(&mut s, "{:?}", x);
26/// }
27/// assert_eq!(s, "\
28/// (0, [1, 2, 3])
29/// (1, [2, 3])
30/// (2, [3])
31/// (3, [])
32/// ");
33/// ```
34#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct HeadTailIter<'a, T> {
36    tail: &'a [T],
37}
38
39impl<'a, T> HeadTailIter<'a, T> {
40    #[must_use]
41    /// Get the previous tail (i.e. the remaining elements).
42    ///
43    /// # Example
44    ///
45    /// ```rust
46    /// use head_tail_iter::HeadTailIterator;
47    ///
48    /// let mut it = [0, 1, 2].head_tail_pairs();
49    /// assert_eq!(it.remainder(), &[0, 1, 2]);
50    /// match it.next() {
51    ///     None => unreachable!(),
52    ///     Some((head, tail)) => {
53    ///         assert_eq!(head, &0);
54    ///         assert_eq!(tail, &[1, 2]);
55    ///         assert_eq!(it.remainder(), &[1, 2]);
56    ///     }
57    /// }
58    /// ```
59    pub fn remainder(&self) -> &'a [T] {
60        self.tail
61    }
62}
63
64impl<'a, T> Iterator for HeadTailIter<'a, T> {
65    type Item = (&'a T, &'a [T]);
66
67    fn next(&mut self) -> Option<Self::Item> {
68        let (head, tail) = self.tail.split_first()?;
69        self.tail = tail;
70        Some((head, tail))
71    }
72
73    fn size_hint(&self) -> (usize, Option<usize>) {
74        let n = self.len();
75        (n, Some(n))
76    }
77    fn count(self) -> usize {
78        self.len()
79    }
80    fn last(self) -> Option<Self::Item> {
81        self.tail.last().map(|t| (t, &[] as &[T]))
82    }
83
84    fn nth(&mut self, n: usize) -> Option<Self::Item> {
85        if n > self.tail.len() {
86            self.tail = &[];
87            None
88        } else {
89            self.tail = &self.tail[n..];
90            self.next()
91        }
92    }
93}
94
95impl<T> FusedIterator for HeadTailIter<'_, T> {}
96impl<T> ExactSizeIterator for HeadTailIter<'_, T> {
97    fn len(&self) -> usize {
98        self.tail.len()
99    }
100}
101
102/// A trait that allows you to get a [`HeadTailIter`]
103/// by calling [`.head_tail_pairs()`](HeadTailIterator::head_tail_pairs`).
104pub trait HeadTailIterator {
105    /// The type parameter for the returned [`HeadTailIter`].
106    type Item;
107
108    /// Create an iterator that yields head & tail of a given slice,
109    /// then head & tail of the tail from the previous step,
110    /// and so on, until there are no more elements left.
111    ///
112    /// Note that at the last step
113    /// the head is the last element of the initial slice,
114    /// and the tail is an empty slice.
115    ///
116    /// This method is implemented for slices, and thus works for arrays, vectors,
117    /// and anything else that [derefs](core::ops::Deref) to a slice.
118    ///
119    /// # Example
120    ///
121    /// ```rust
122    /// # use head_tail_iter::HeadTailIterator;
123    /// for (head, tail) in vec![3, 2, 1, 0].head_tail_pairs() {
124    ///     assert_eq!(*head, tail.len());
125    /// }
126    /// ```
127    #[must_use]
128    fn head_tail_pairs(&self) -> HeadTailIter<'_, Self::Item>;
129}
130
131impl<T> HeadTailIterator for [T] {
132    type Item = T;
133
134    #[inline]
135    fn head_tail_pairs(&self) -> HeadTailIter<'_, Self::Item> {
136        HeadTailIter { tail: self }
137    }
138}
139
140impl<'a, T> From<&'a T> for HeadTailIter<'a, <T as HeadTailIterator>::Item>
141where
142    T: HeadTailIterator + ?Sized,
143{
144    #[inline]
145    fn from(value: &'a T) -> Self {
146        value.head_tail_pairs()
147    }
148}