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
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use super::{MarkdownExt, Share, FrontMatter};
use std::cell::{Ref, RefCell};

enum AfterState {
    Origin,
    Pseudo,
}

/// An iterator places events after the first occurrence of certain event.
///
/// This `struct` is created by [`after`] method on [`MarkdownExt`].
///
/// [`after`]: trait.MarkdownExt.html#method.after
/// [`MarkdownExt`]: trait.MarkdownExt.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(new)]
pub struct After<I, S, G, F, P, T>
where
    I: Iterator<Item = T>,
    S: Iterator<Item = T>,
    G: IntoIterator<Item = T, IntoIter = S>,
    F: Fn(Ref<Option<FrontMatter>>) -> G,
    P: Fn(&T) -> bool,
{
    frontmatter: Share<RefCell<Option<FrontMatter>>>,
    iter: I,
    after: P,

    // Create pseudo iter
    f: F,

    // Delay its construction until needed
    #[new(default)]
    pseudo: Option<S>,
    #[new(value = "AfterState::Origin")]
    state: AfterState,
}

impl<I, S, G, F, P, T> MarkdownExt<T> for After<I, S, G, F, P, T>
where
    I: Iterator<Item = T>,
    S: Iterator<Item = T>,
    G: IntoIterator<Item = T, IntoIter = S>,
    F: Fn(Ref<Option<FrontMatter>>) -> G,
    P: Fn(&T) -> bool,
{
    fn frontmatter(&mut self) -> &mut Share<RefCell<Option<FrontMatter>>> {
        &mut self.frontmatter
    }
}

impl<I, S, G, F, P, T> Iterator for After<I, S, G, F, P, T>
where
    I: Iterator<Item = T>,
    S: Iterator<Item = T>,
    G: IntoIterator<Item = T, IntoIter = S>,
    F: Fn(Ref<Option<FrontMatter>>) -> G,
    P: Fn(&T) -> bool,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        match self.state {
            AfterState::Origin => match self.iter.next() {
                // If current item match the predication, return it and switch to
                // pseudo iterator.
                Some(t) if (self.after)(&t) => {
                    self.state = AfterState::Pseudo;
                    Some(t)
                }
                otherwise => otherwise,
            },
            // We need to check if the pseudo iterator has been created or not.
            AfterState::Pseudo => match self.pseudo.as_mut() {
                Some(iter) => match iter.next() {
                    node @ Some(_) => node,
                    // The whole pseudo iterator has been consumed, hand back to
                    // the original iterator.
                    None => {
                        self.state = AfterState::Origin;
                        self.iter.next()
                    }
                },
                None => {
                    self.pseudo = Some(
                        (self.f)(self.frontmatter.upgrade().unwrap().borrow()).into_iter(),
                    );

                    // Since we've written something into self.pseudo, it would definitely
                    // go to the Some arm above
                    self.next()
                }
            },
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::iter::{empty, once};
    use std::rc::Rc;

    #[test]
    fn only_once() {
        assert_eq!(
            After::new(
                Rc::new(RefCell::new(None)).into(),
                1..5,
                |&n| n % 2 == 0,
                |_| once(0)
            )
            .collect::<Vec<_>>(),
            vec![1, 2, 0, 3, 4]
        );
    }

    #[test]
    fn empty_pseudo() {
        assert_eq!(
            After::new(
                Rc::new(RefCell::new(None)).into(),
                1..5,
                |&n| n % 2 == 0,
                |_| empty()
            )
            .collect::<Vec<_>>(),
            vec![1, 2, 3, 4]
        );
    }

    #[test]
    fn never_match() {
        assert_eq!(
            After::new(
                Rc::new(RefCell::new(None)).into(),
                1..5,
                |&n| n % 2 == 5,
                |_| once(0)
            )
            .collect::<Vec<_>>(),
            vec![1, 2, 3, 4]
        );
    }

    #[test]
    fn lazy() {
        assert!(After::new(
                Rc::new(RefCell::new(None)).into(),
            1..5,
            |&n| n % 10 == 0,
            |_| once(0)
        )
        .pseudo
        .is_none());
    }
}