//! Misc helper functions and types for use in parsing network documents

pub(crate) mod intern;
pub(crate) mod str;

use std::iter::Peekable;

/// An iterator adaptor that pauses when a given predicate is true.
///
/// Unlike std::iter::TakeWhile, it doesn't consume the first non-returned
/// element.
///
/// We guarantee that the predicate is called no more than once for
/// each item.
pub(crate) struct PauseAt<'a, I: Iterator, F: FnMut(&I::Item) -> bool> {
    /// An underlying iterator that we should take items from
    peek: &'a mut Peekable<I>,
    /// A predicate telling us which items mean that we should pause
    pred: F,
    /// Memoized value of self.pred(self.peek()), so we never
    /// calculate it more than once.
    paused: Option<bool>,
}

impl<'a, I: Iterator, F: FnMut(&I::Item) -> bool> PauseAt<'a, I, F> {
    /// Construct a PauseAt that will pause the iterator `peek` when the
    /// predicate `pred` is about to be true.
    pub(crate) fn from_peekable(peek: &'a mut Peekable<I>, pred: F) -> Self
    where
        F: FnMut(&I::Item) -> bool,
    {
        PauseAt {
            peek,
            pred,
            paused: None,
        }
    }
    /// Replace the predicate on a PauseAt, returning a new PauseAt.
    #[cfg(any(test, feature = "routerdesc"))]
    pub(crate) fn new_pred<F2>(self, pred: F2) -> PauseAt<'a, I, F2>
    where
        F2: FnMut(&I::Item) -> bool,
    {
        PauseAt::from_peekable(self.peek, pred)
    }
    /// Unwrap this PauseAt, returning its underlying Peekable.
    #[allow(unused)]
    pub(crate) fn remaining(self) -> &'a mut Peekable<I> {
        self.peek
    }
    /// Return the next item that will be yielded from this iterator, or
    /// None if this iterator is about to yield None.
    #[allow(unused)]
    pub(crate) fn peek(&mut self) -> Option<&I::Item> {
        // TODO: I wish it weren't necessary for this function to take
        // a mutable reference.
        if self.check_paused() {
            None
        } else {
            self.peek.peek()
        }
    }
    /// Helper: Return true if we will pause before the next element,
    /// and false otherwise.  Store the value in self.paused, so that
    /// we don't invoke self.pred more than once.
    fn check_paused(&mut self) -> bool {
        if let Some(p) = self.paused {
            return p;
        }
        if let Some(nextval) = self.peek.peek() {
            let p = (self.pred)(nextval);
            self.paused = Some(p);
            p
        } else {
            self.paused = Some(false);
            false
        }
    }
}

impl<'a, I: Iterator, F: FnMut(&I::Item) -> bool> Iterator for PauseAt<'a, I, F> {
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        if self.check_paused() {
            None
        } else {
            self.paused = None;
            self.peek.next()
        }
    }
}

/// A Private module for declaring a "sealed" trait.
pub(crate) mod private {
    /// A non-exported trait, used to prevent others from implementing a trait.
    ///
    /// For more information on this pattern, see [the Rust API
    /// guidelines](https://rust-lang.github.io/api-guidelines/future-proofing.html#c-sealed).
    pub trait Sealed {}
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_pause_at() {
        use super::PauseAt;
        let mut iter = (1..10).into_iter().peekable();
        let mut iter = PauseAt::from_peekable(&mut iter, |x| *x == 3);

        assert_eq!(iter.next(), Some(1));
        assert_eq!(iter.next(), Some(2));
        assert_eq!(iter.next(), None);

        let mut iter = iter.new_pred(|x| *x > 5);
        assert_eq!(iter.next(), Some(3));
        assert_eq!(iter.next(), Some(4));
        assert_eq!(iter.next(), Some(5));
        assert_eq!(iter.peek(), None);
        assert_eq!(iter.next(), None);

        let iter = iter.remaining();
        assert_eq!(iter.next(), Some(6));
        assert_eq!(iter.peek(), Some(&7));
        assert_eq!(iter.next(), Some(7));
        assert_eq!(iter.next(), Some(8));
        assert_eq!(iter.next(), Some(9));
        assert_eq!(iter.peek(), None);
        assert_eq!(iter.next(), None);
    }

    #[test]
    fn test_parse_at_mutable() {
        use super::PauseAt;
        let mut count = 0;
        let mut iter = (1..10).into_iter().peekable();
        // pause at the third item, using mutable state in the closure.
        let mut iter = PauseAt::from_peekable(&mut iter, |_| {
            count += 1;
            count == 4
        });
        assert_eq!(iter.peek(), Some(&1)); // we can do this multiple times,
        assert_eq!(iter.peek(), Some(&1)); // but count isn't advanced.
        assert_eq!(iter.next(), Some(1));

        assert_eq!(iter.next(), Some(2));
        assert_eq!(iter.peek(), Some(&3));
        assert_eq!(iter.next(), Some(3));
        assert_eq!(iter.peek(), None);
        assert_eq!(iter.next(), None);
    }
}
