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
use crate::{MarkdownExt, Share, FrontMatter};
use std::cell::RefCell;

enum LinkState {
    Front,
    Back,
}

/// An iterator links two [`MarkdownExt`].
///
/// This `struct` is created by [`link`] method on [`MarkdownExt`].
///
/// [`link`]: trait.MarkdownExt.html#method.link
/// [`MarkdownExt`]: trait.MarkdownExt.html
#[derive(new)]
pub struct Link<A, B> {
    frontmatter: Share<RefCell<Option<FrontMatter>>>,
    a: A,
    b: B,

    #[new(value = "LinkState::Front")]
    state: LinkState,
}

impl<A, B, T> MarkdownExt<T> for Link<A, B>
where
    A: Iterator<Item = T>,
    B: Iterator<Item = T>,
{
    fn frontmatter(&mut self) -> &mut Share<RefCell<Option<FrontMatter>>> {
        &mut self.frontmatter
    }
}

impl<A, B, T> Iterator for Link<A, B>
where
    A: Iterator<Item = T>,
    B: Iterator<Item = T>,
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        match self.state {
            LinkState::Front => match self.a.next() {
                node @ Some(_) => node,
                None => {
                    self.state = LinkState::Back;
                    self.b.next()
                }
            },
            LinkState::Back => self.b.next(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::rc::Rc;

    struct TestIter {
        frontmatter: Share<RefCell<Option<FrontMatter>>>,
        range: std::ops::Range<u8>,
    }

    impl From<std::ops::Range<u8>> for TestIter {
        fn from(r: std::ops::Range<u8>) -> Self {
            Self {
                frontmatter: Rc::new(RefCell::new(None)).into(),
                range: r,
            }
        }
    }

    impl Iterator for TestIter {
        type Item = u8;

        fn next(&mut self) -> Option<Self::Item> {
            self.range.next()
        }
    }

    impl MarkdownExt<u8> for TestIter {
        fn frontmatter(&mut self) -> &mut Share<RefCell<Option<FrontMatter>>> {
            &mut self.frontmatter
        }
    }

    #[test]
    fn iter() {
        assert_eq!(
            Link::new(
                Rc::new(RefCell::new(None)).into(),
                TestIter::from(1..4),
                TestIter::from(4..7),
            )
            .collect::<Vec<_>>(),
            (1..7).collect::<Vec<_>>()
        );
    }
}