Coverage Report

Created: 2025-10-10 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/itertools-0.12.1/src/tuple_impl.rs
Line
Count
Source
1
//! Some iterator that produces tuples
2
3
use std::iter::Cycle;
4
use std::iter::Fuse;
5
use std::iter::FusedIterator;
6
7
use crate::size_hint;
8
9
// `HomogeneousTuple` is a public facade for `TupleCollect`, allowing
10
// tuple-related methods to be used by clients in generic contexts, while
11
// hiding the implementation details of `TupleCollect`.
12
// See https://github.com/rust-itertools/itertools/issues/387
13
14
/// Implemented for homogeneous tuples of size up to 12.
15
pub trait HomogeneousTuple: TupleCollect {}
16
17
impl<T: TupleCollect> HomogeneousTuple for T {}
18
19
/// An iterator over a incomplete tuple.
20
///
21
/// See [`.tuples()`](crate::Itertools::tuples) and
22
/// [`Tuples::into_buffer()`].
23
#[derive(Clone, Debug)]
24
pub struct TupleBuffer<T>
25
where
26
    T: HomogeneousTuple,
27
{
28
    cur: usize,
29
    buf: T::Buffer,
30
}
31
32
impl<T> TupleBuffer<T>
33
where
34
    T: HomogeneousTuple,
35
{
36
0
    fn new(buf: T::Buffer) -> Self {
37
0
        Self { cur: 0, buf }
38
0
    }
39
}
40
41
impl<T> Iterator for TupleBuffer<T>
42
where
43
    T: HomogeneousTuple,
44
{
45
    type Item = T::Item;
46
47
0
    fn next(&mut self) -> Option<Self::Item> {
48
0
        let s = self.buf.as_mut();
49
0
        if let Some(ref mut item) = s.get_mut(self.cur) {
50
0
            self.cur += 1;
51
0
            item.take()
52
        } else {
53
0
            None
54
        }
55
0
    }
56
57
0
    fn size_hint(&self) -> (usize, Option<usize>) {
58
0
        let buffer = &self.buf.as_ref()[self.cur..];
59
0
        let len = if buffer.is_empty() {
60
0
            0
61
        } else {
62
0
            buffer
63
0
                .iter()
64
0
                .position(|x| x.is_none())
65
0
                .unwrap_or(buffer.len())
66
        };
67
0
        (len, Some(len))
68
0
    }
69
}
70
71
impl<T> ExactSizeIterator for TupleBuffer<T> where T: HomogeneousTuple {}
72
73
/// An iterator that groups the items in tuples of a specific size.
74
///
75
/// See [`.tuples()`](crate::Itertools::tuples) for more information.
76
#[derive(Clone, Debug)]
77
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
78
pub struct Tuples<I, T>
79
where
80
    I: Iterator<Item = T::Item>,
81
    T: HomogeneousTuple,
82
{
83
    iter: Fuse<I>,
84
    buf: T::Buffer,
85
}
86
87
/// Create a new tuples iterator.
88
0
pub fn tuples<I, T>(iter: I) -> Tuples<I, T>
89
0
where
90
0
    I: Iterator<Item = T::Item>,
91
0
    T: HomogeneousTuple,
92
{
93
0
    Tuples {
94
0
        iter: iter.fuse(),
95
0
        buf: Default::default(),
96
0
    }
97
0
}
98
99
impl<I, T> Iterator for Tuples<I, T>
100
where
101
    I: Iterator<Item = T::Item>,
102
    T: HomogeneousTuple,
103
{
104
    type Item = T;
105
106
0
    fn next(&mut self) -> Option<Self::Item> {
107
0
        T::collect_from_iter(&mut self.iter, &mut self.buf)
108
0
    }
109
110
0
    fn size_hint(&self) -> (usize, Option<usize>) {
111
        // The number of elts we've drawn from the underlying iterator, but have
112
        // not yet produced as a tuple.
113
0
        let buffered = T::buffer_len(&self.buf);
114
        // To that, we must add the size estimates of the underlying iterator.
115
0
        let (unbuffered_lo, unbuffered_hi) = self.iter.size_hint();
116
        // The total low estimate is the sum of the already-buffered elements,
117
        // plus the low estimate of remaining unbuffered elements, divided by
118
        // the tuple size.
119
0
        let total_lo = add_then_div(unbuffered_lo, buffered, T::num_items()).unwrap_or(usize::MAX);
120
        // And likewise for the total high estimate, but using the high estimate
121
        // of the remaining unbuffered elements.
122
0
        let total_hi = unbuffered_hi.and_then(|hi| add_then_div(hi, buffered, T::num_items()));
123
0
        (total_lo, total_hi)
124
0
    }
125
}
126
127
/// `(n + a) / d` avoiding overflow when possible, returns `None` if it overflows.
128
0
fn add_then_div(n: usize, a: usize, d: usize) -> Option<usize> {
129
0
    debug_assert_ne!(d, 0);
130
0
    (n / d).checked_add(a / d)?.checked_add((n % d + a % d) / d)
131
0
}
132
133
impl<I, T> ExactSizeIterator for Tuples<I, T>
134
where
135
    I: ExactSizeIterator<Item = T::Item>,
136
    T: HomogeneousTuple,
137
{
138
}
139
140
impl<I, T> Tuples<I, T>
141
where
142
    I: Iterator<Item = T::Item>,
143
    T: HomogeneousTuple,
144
{
145
    /// Return a buffer with the produced items that was not enough to be grouped in a tuple.
146
    ///
147
    /// ```
148
    /// use itertools::Itertools;
149
    ///
150
    /// let mut iter = (0..5).tuples();
151
    /// assert_eq!(Some((0, 1, 2)), iter.next());
152
    /// assert_eq!(None, iter.next());
153
    /// itertools::assert_equal(vec![3, 4], iter.into_buffer());
154
    /// ```
155
0
    pub fn into_buffer(self) -> TupleBuffer<T> {
156
0
        TupleBuffer::new(self.buf)
157
0
    }
158
}
159
160
/// An iterator over all contiguous windows that produces tuples of a specific size.
161
///
162
/// See [`.tuple_windows()`](crate::Itertools::tuple_windows) for more
163
/// information.
164
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
165
#[derive(Clone, Debug)]
166
pub struct TupleWindows<I, T>
167
where
168
    I: Iterator<Item = T::Item>,
169
    T: HomogeneousTuple,
170
{
171
    iter: I,
172
    last: Option<T>,
173
}
174
175
/// Create a new tuple windows iterator.
176
0
pub fn tuple_windows<I, T>(iter: I) -> TupleWindows<I, T>
177
0
where
178
0
    I: Iterator<Item = T::Item>,
179
0
    T: HomogeneousTuple,
180
0
    T::Item: Clone,
181
{
182
0
    TupleWindows { last: None, iter }
183
0
}
184
185
impl<I, T> Iterator for TupleWindows<I, T>
186
where
187
    I: Iterator<Item = T::Item>,
188
    T: HomogeneousTuple + Clone,
189
    T::Item: Clone,
190
{
191
    type Item = T;
192
193
0
    fn next(&mut self) -> Option<Self::Item> {
194
0
        if T::num_items() == 1 {
195
0
            return T::collect_from_iter_no_buf(&mut self.iter);
196
0
        }
197
0
        if let Some(new) = self.iter.next() {
198
0
            if let Some(ref mut last) = self.last {
199
0
                last.left_shift_push(new);
200
0
                Some(last.clone())
201
            } else {
202
                use std::iter::once;
203
0
                let iter = once(new).chain(&mut self.iter);
204
0
                self.last = T::collect_from_iter_no_buf(iter);
205
0
                self.last.clone()
206
            }
207
        } else {
208
0
            None
209
        }
210
0
    }
211
212
0
    fn size_hint(&self) -> (usize, Option<usize>) {
213
0
        let mut sh = self.iter.size_hint();
214
        // Adjust the size hint at the beginning
215
        // OR when `num_items == 1` (but it does not change the size hint).
216
0
        if self.last.is_none() {
217
0
            sh = size_hint::sub_scalar(sh, T::num_items() - 1);
218
0
        }
219
0
        sh
220
0
    }
221
}
222
223
impl<I, T> ExactSizeIterator for TupleWindows<I, T>
224
where
225
    I: ExactSizeIterator<Item = T::Item>,
226
    T: HomogeneousTuple + Clone,
227
    T::Item: Clone,
228
{
229
}
230
231
impl<I, T> FusedIterator for TupleWindows<I, T>
232
where
233
    I: FusedIterator<Item = T::Item>,
234
    T: HomogeneousTuple + Clone,
235
    T::Item: Clone,
236
{
237
}
238
239
/// An iterator over all windows, wrapping back to the first elements when the
240
/// window would otherwise exceed the length of the iterator, producing tuples
241
/// of a specific size.
242
///
243
/// See [`.circular_tuple_windows()`](crate::Itertools::circular_tuple_windows) for more
244
/// information.
245
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
246
#[derive(Debug, Clone)]
247
pub struct CircularTupleWindows<I, T>
248
where
249
    I: Iterator<Item = T::Item> + Clone,
250
    T: TupleCollect + Clone,
251
{
252
    iter: TupleWindows<Cycle<I>, T>,
253
    len: usize,
254
}
255
256
0
pub fn circular_tuple_windows<I, T>(iter: I) -> CircularTupleWindows<I, T>
257
0
where
258
0
    I: Iterator<Item = T::Item> + Clone + ExactSizeIterator,
259
0
    T: TupleCollect + Clone,
260
0
    T::Item: Clone,
261
{
262
0
    let len = iter.len();
263
0
    let iter = tuple_windows(iter.cycle());
264
265
0
    CircularTupleWindows { iter, len }
266
0
}
267
268
impl<I, T> Iterator for CircularTupleWindows<I, T>
269
where
270
    I: Iterator<Item = T::Item> + Clone,
271
    T: TupleCollect + Clone,
272
    T::Item: Clone,
273
{
274
    type Item = T;
275
276
0
    fn next(&mut self) -> Option<Self::Item> {
277
0
        if self.len != 0 {
278
0
            self.len -= 1;
279
0
            self.iter.next()
280
        } else {
281
0
            None
282
        }
283
0
    }
284
285
0
    fn size_hint(&self) -> (usize, Option<usize>) {
286
0
        (self.len, Some(self.len))
287
0
    }
288
}
289
290
impl<I, T> ExactSizeIterator for CircularTupleWindows<I, T>
291
where
292
    I: Iterator<Item = T::Item> + Clone,
293
    T: TupleCollect + Clone,
294
    T::Item: Clone,
295
{
296
}
297
298
impl<I, T> FusedIterator for CircularTupleWindows<I, T>
299
where
300
    I: Iterator<Item = T::Item> + Clone,
301
    T: TupleCollect + Clone,
302
    T::Item: Clone,
303
{
304
}
305
306
pub trait TupleCollect: Sized {
307
    type Item;
308
    type Buffer: Default + AsRef<[Option<Self::Item>]> + AsMut<[Option<Self::Item>]>;
309
310
0
    fn buffer_len(buf: &Self::Buffer) -> usize {
311
0
        let s = buf.as_ref();
312
0
        s.iter().position(Option::is_none).unwrap_or(s.len())
313
0
    }
314
315
    fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
316
    where
317
        I: IntoIterator<Item = Self::Item>;
318
319
    fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
320
    where
321
        I: IntoIterator<Item = Self::Item>;
322
323
    fn num_items() -> usize;
324
325
    fn left_shift_push(&mut self, item: Self::Item);
326
}
327
328
macro_rules! rev_for_each_ident{
329
    ($m:ident, ) => {};
330
    ($m:ident, $i0:ident, $($i:ident,)*) => {
331
        rev_for_each_ident!($m, $($i,)*);
332
        $m!($i0);
333
    };
334
}
335
336
macro_rules! impl_tuple_collect {
337
    ($dummy:ident,) => {}; // stop
338
    ($dummy:ident, $($Y:ident,)*) => (
339
        impl_tuple_collect!($($Y,)*);
340
        impl<A> TupleCollect for ($(ignore_ident!($Y, A),)*) {
341
            type Item = A;
342
            type Buffer = [Option<A>; count_ident!($($Y)*) - 1];
343
344
            #[allow(unused_assignments, unused_mut)]
345
0
            fn collect_from_iter<I>(iter: I, buf: &mut Self::Buffer) -> Option<Self>
346
0
                where I: IntoIterator<Item = A>
347
            {
348
0
                let mut iter = iter.into_iter();
349
                $(
350
0
                    let mut $Y = None;
351
                )*
352
353
                loop {
354
                    $(
355
0
                        $Y = iter.next();
356
0
                        if $Y.is_none() {
357
0
                            break
358
0
                        }
359
                    )*
360
0
                    return Some(($($Y.unwrap()),*,))
361
                }
362
363
0
                let mut i = 0;
364
0
                let mut s = buf.as_mut();
365
                $(
366
0
                    if i < s.len() {
367
0
                        s[i] = $Y;
368
0
                        i += 1;
369
0
                    }
370
                )*
371
0
                return None;
372
0
            }
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
Unexecuted instantiation: <(_, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
Unexecuted instantiation: <(_, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
Unexecuted instantiation: <(_, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
Unexecuted instantiation: <(_, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
Unexecuted instantiation: <(_, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
Unexecuted instantiation: <(_, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
Unexecuted instantiation: <(_, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
Unexecuted instantiation: <(_,) as itertools::tuple_impl::TupleCollect>::collect_from_iter::<_>
373
374
0
            fn collect_from_iter_no_buf<I>(iter: I) -> Option<Self>
375
0
                where I: IntoIterator<Item = A>
376
            {
377
0
                let mut iter = iter.into_iter();
378
379
                Some(($(
380
0
                    { let $Y = iter.next()?; $Y },
381
                )*))
382
0
            }
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
Unexecuted instantiation: <(_, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
Unexecuted instantiation: <(_, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
Unexecuted instantiation: <(_, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
Unexecuted instantiation: <(_, _, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
Unexecuted instantiation: <(_, _, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
Unexecuted instantiation: <(_, _, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
Unexecuted instantiation: <(_, _) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
Unexecuted instantiation: <(_,) as itertools::tuple_impl::TupleCollect>::collect_from_iter_no_buf::<_>
383
384
0
            fn num_items() -> usize {
385
0
                count_ident!($($Y)*)
386
0
            }
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::num_items
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::num_items
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::num_items
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::num_items
Unexecuted instantiation: <(_, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::num_items
Unexecuted instantiation: <(_, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::num_items
Unexecuted instantiation: <(_, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::num_items
Unexecuted instantiation: <(_, _, _, _, _) as itertools::tuple_impl::TupleCollect>::num_items
Unexecuted instantiation: <(_, _, _, _) as itertools::tuple_impl::TupleCollect>::num_items
Unexecuted instantiation: <(_, _, _) as itertools::tuple_impl::TupleCollect>::num_items
Unexecuted instantiation: <(_, _) as itertools::tuple_impl::TupleCollect>::num_items
Unexecuted instantiation: <(_,) as itertools::tuple_impl::TupleCollect>::num_items
387
388
0
            fn left_shift_push(&mut self, mut item: A) {
389
                use std::mem::replace;
390
391
0
                let &mut ($(ref mut $Y),*,) = self;
392
                macro_rules! replace_item{($i:ident) => {
393
                    item = replace($i, item);
394
                }}
395
0
                rev_for_each_ident!(replace_item, $($Y,)*);
396
0
                drop(item);
397
0
            }
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::left_shift_push
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::left_shift_push
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::left_shift_push
Unexecuted instantiation: <(_, _, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::left_shift_push
Unexecuted instantiation: <(_, _, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::left_shift_push
Unexecuted instantiation: <(_, _, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::left_shift_push
Unexecuted instantiation: <(_, _, _, _, _, _) as itertools::tuple_impl::TupleCollect>::left_shift_push
Unexecuted instantiation: <(_, _, _, _, _) as itertools::tuple_impl::TupleCollect>::left_shift_push
Unexecuted instantiation: <(_, _, _, _) as itertools::tuple_impl::TupleCollect>::left_shift_push
Unexecuted instantiation: <(_, _, _) as itertools::tuple_impl::TupleCollect>::left_shift_push
Unexecuted instantiation: <(_, _) as itertools::tuple_impl::TupleCollect>::left_shift_push
Unexecuted instantiation: <(_,) as itertools::tuple_impl::TupleCollect>::left_shift_push
398
        }
399
    )
400
}
401
impl_tuple_collect!(dummy, a, b, c, d, e, f, g, h, i, j, k, l,);