<commit_before>//! Basic combinators.

use ::{ParseResult, Input};

use ::iter::{EndState, Iter};

use ::internal::State;
use ::internal::{ParseResultModify, InputModify};
use ::internal::{data, error, incomplete};

use ::std::iter::FromIterator;

/// Applies the parser ``p`` exactly ``num`` times, propagating any error or incomplete state.
/// 
/// ```
/// use chomp::{ParseResult, Error, Input, count, token, take_remainder};
/// 
/// let p1 = Input::new(b"a  ");
/// let p2 = Input::new(b"aa ");
/// let p3 = Input::new(b"aaa");
/// 
/// fn parse(i: Input<u8>) -> ParseResult<u8, Vec<u8>, Error<u8>> {
///     count(i, 2, |i| token(i, b'a'))
/// }
/// 
/// assert_eq!(parse(p1).unwrap_err(), Error::Expected(b'a'));
/// assert_eq!(parse(p2).unwrap(), &[b'a', b'a']);
/// 
/// // TODO: Update once a proper way to extract data and remainder has been implemented
/// // a slightly odd way to obtain the remainder of the input stream, temporary
/// let d: ParseResult<_, (_, Vec<_>), Error<_>> = parse(p3).bind(|i, d| take_remainder(i).bind(|i, r| i.ret((r, d))));
/// let (buf, data) = d.unwrap();
/// 
/// assert_eq!(buf, b"a");
/// assert_eq!(data, &[b'a', b'a']);
/// ```
#[inline]
pub fn count<'a, I, T, E, F, U>(i: Input<'a, I>, num: usize, p: F) -> ParseResult<'a, I, T, E>
  where I: Copy,
        U: 'a,
        F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
        T: FromIterator<U> {
    i.parse(|i| {
        // If we have gotten an item, if this is false after from_iter we have failed
        let mut count = 0;
        let mut iter  = Iter::new(i, p);

        let result: T      = FromIterator::from_iter(iter.by_ref().take(num).inspect(|_| count = count + 1 ));
        let (buffer, last) = iter.end_state();

        if count == num {
            data(buffer, result)
        } else {
            // Can only be less than num here since take() limits it.
            // Just propagate the last state from the iterator.
            match last {
                EndState::Incomplete(n) => incomplete(n),
                EndState::Error(b, e)   => error(b, e),
            }
        }
    })
}

/// Tries the parser ``f``, on success it yields the parsed value, on failure ``default`` will be
/// yielded instead.
/// 
/// Incomplete state is propagated.
/// 
/// ```
/// use chomp::{Input, option, token};
/// 
/// let p1 = Input::new(b"abc");
/// let p2 = Input::new(b"bbc");
/// 
/// assert_eq!(option(p1, |i| token(i, b'a'), b'd').unwrap(), b'a');
/// assert_eq!(option(p2, |i| token(i, b'a'), b'd').unwrap(), b'd');
/// ```
#[inline]
pub fn option<'a, I, T, E, F>(i: Input<'a, I>, f: F, default: T) -> ParseResult<'a, I, T, E>
  where I: 'a + Copy,
        F: FnOnce(Input<'a, I>) -> ParseResult<'a, I, T, E> {
    // TODO: That Input::new should be something related to InputModify
    i.parse(|b| f(Input::new(b)).parse(|s| match s {
        State::Data(b, t)    => data(b, t),
        State::Error(_, _)   => data(b, default),
        State::Incomplete(n) => incomplete(n),
    }))
}

/// Tries to match the parser ``f``, if ``f`` fails it tries ``g``. Returns the success value of
/// the first match, otherwise the error of the last one if both fail.
/// 
/// Incomplete state is propagated from the first one to report incomplete.
/// <commit_msg>option: small note about backtracking<commit_after>//! Basic combinators.

use ::{ParseResult, Input};

use ::iter::{EndState, Iter};

use ::internal::State;
use ::internal::{ParseResultModify, InputModify};
use ::internal::{data, error, incomplete};

use ::std::iter::FromIterator;

/// Applies the parser ``p`` exactly ``num`` times, propagating any error or incomplete state.
/// 
/// ```
/// use chomp::{ParseResult, Error, Input, count, token, take_remainder};
/// 
/// let p1 = Input::new(b"a  ");
/// let p2 = Input::new(b"aa ");
/// let p3 = Input::new(b"aaa");
/// 
/// fn parse(i: Input<u8>) -> ParseResult<u8, Vec<u8>, Error<u8>> {
///     count(i, 2, |i| token(i, b'a'))
/// }
/// 
/// assert_eq!(parse(p1).unwrap_err(), Error::Expected(b'a'));
/// assert_eq!(parse(p2).unwrap(), &[b'a', b'a']);
/// 
/// // TODO: Update once a proper way to extract data and remainder has been implemented
/// // a slightly odd way to obtain the remainder of the input stream, temporary
/// let d: ParseResult<_, (_, Vec<_>), Error<_>> = parse(p3).bind(|i, d| take_remainder(i).bind(|i, r| i.ret((r, d))));
/// let (buf, data) = d.unwrap();
/// 
/// assert_eq!(buf, b"a");
/// assert_eq!(data, &[b'a', b'a']);
/// ```
#[inline]
pub fn count<'a, I, T, E, F, U>(i: Input<'a, I>, num: usize, p: F) -> ParseResult<'a, I, T, E>
  where I: Copy,
        U: 'a,
        F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
        T: FromIterator<U> {
    i.parse(|i| {
        // If we have gotten an item, if this is false after from_iter we have failed
        let mut count = 0;
        let mut iter  = Iter::new(i, p);

        let result: T      = FromIterator::from_iter(iter.by_ref().take(num).inspect(|_| count = count + 1 ));
        let (buffer, last) = iter.end_state();

        if count == num {
            data(buffer, result)
        } else {
            // Can only be less than num here since take() limits it.
            // Just propagate the last state from the iterator.
            match last {
                EndState::Incomplete(n) => incomplete(n),
                EndState::Error(b, e)   => error(b, e),
            }
        }
    })
}

/// Tries the parser ``f``, on success it yields the parsed value, on failure ``default`` will be
/// yielded instead.
/// 
/// Incomplete state is propagated. Backtracks on error.
/// 
/// ```
/// use chomp::{Input, option, token};
/// 
/// let p1 = Input::new(b"abc");
/// let p2 = Input::new(b"bbc");
/// 
/// assert_eq!(option(p1, |i| token(i, b'a'), b'd').unwrap(), b'a');
/// assert_eq!(option(p2, |i| token(i, b'a'), b'd').unwrap(), b'd');
/// ```
#[inline]
pub fn option<'a, I, T, E, F>(i: Input<'a, I>, f: F, default: T) -> ParseResult<'a, I, T, E>
  where I: 'a + Copy,
        F: FnOnce(Input<'a, I>) -> ParseResult<'a, I, T, E> {
    // TODO: That Input::new should be something related to InputModify
    i.parse(|b| f(Input::new(b)).parse(|s| match s {
        State::Data(b, t)    => data(b, t),
        State::Error(_, _)   => data(b, default),
        State::Incomplete(n) => incomplete(n),
    }))
}

/// Tries to match the parser ``f``, if ``f`` fails it tries ``g``. Returns the success value of
/// the first match, otherwise the error of the last one if both fail.
/// 
/// Incomplete state is propagated from the first one to report incomplete.
/// 
{'fraction_non_alphanumeric': 0.21546376153729763, 'fraction_numerical': 0.005144499924345589, 'mean_word_length': 2.6742634797109504, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1830842', 'n_tokens_mistral': 2319, 'n_tokens_neox': 2320, 'n_words': 707}