summaryrefslogtreecommitdiffstats
path: root/third_party/rust/itertools/src/tee.rs
blob: ea4752906f0580dfaf4e49d2d8df13f812f2f244 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use super::size_hint;

use std::cell::RefCell;
use alloc::collections::VecDeque;
use alloc::rc::Rc;

/// Common buffer object for the two tee halves
#[derive(Debug)]
struct TeeBuffer<A, I> {
    backlog: VecDeque<A>,
    iter: I,
    /// The owner field indicates which id should read from the backlog
    owner: bool,
}

/// One half of an iterator pair where both return the same elements.
///
/// See [`.tee()`](crate::Itertools::tee) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct Tee<I>
    where I: Iterator
{
    rcbuffer: Rc<RefCell<TeeBuffer<I::Item, I>>>,
    id: bool,
}

pub fn new<I>(iter: I) -> (Tee<I>, Tee<I>)
    where I: Iterator
{
    let buffer = TeeBuffer{backlog: VecDeque::new(), iter, owner: false};
    let t1 = Tee{rcbuffer: Rc::new(RefCell::new(buffer)), id: true};
    let t2 = Tee{rcbuffer: t1.rcbuffer.clone(), id: false};
    (t1, t2)
}

impl<I> Iterator for Tee<I>
    where I: Iterator,
          I::Item: Clone
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        // .borrow_mut may fail here -- but only if the user has tied some kind of weird
        // knot where the iterator refers back to itself.
        let mut buffer = self.rcbuffer.borrow_mut();
        if buffer.owner == self.id {
            match buffer.backlog.pop_front() {
                None => {}
                some_elt => return some_elt,
            }
        }
        match buffer.iter.next() {
            None => None,
            Some(elt) => {
                buffer.backlog.push_back(elt.clone());
                buffer.owner = !self.id;
                Some(elt)
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let buffer = self.rcbuffer.borrow();
        let sh = buffer.iter.size_hint();

        if buffer.owner == self.id {
            let log_len = buffer.backlog.len();
            size_hint::add_scalar(sh, log_len)
        } else {
            sh
        }
    }
}

impl<I> ExactSizeIterator for Tee<I>
    where I: ExactSizeIterator,
          I::Item: Clone
{}