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}