aoc-parse 0.2.17

A little library for parsing your Advent of Code puzzle input
Documentation
//! Alternation.

use crate::{
    parsers::{empty, map, EmptyParser, MapParser},
    types::ParserOutput,
    ParseContext, ParseIter, Parser, Reported, Result,
};

#[derive(Debug, PartialEq, Eq)]
pub enum Either<A, B> {
    Left(A),
    Right(B),
}

#[derive(Copy, Clone)]
pub struct EitherParser<A, B> {
    left: A,
    right: B,
}

pub struct EitherParseIter<'parse, A, B>
where
    A: Parser + 'parse,
    B: Parser + 'parse,
{
    start: usize,
    parsers: &'parse EitherParser<A, B>,
    iter: Either<A::Iter<'parse>, B::Iter<'parse>>,
}

impl<A, B> Parser for EitherParser<A, B>
where
    A: Parser,
    B: Parser,
{
    type Output = Either<A::Output, B::Output>;
    type RawOutput = (Either<A::Output, B::Output>,);
    type Iter<'parse> = EitherParseIter<'parse, A, B>
    where
        A: 'parse,
        B: 'parse;

    fn parse_iter<'parse>(
        &'parse self,
        context: &mut ParseContext<'parse>,
        start: usize,
    ) -> Result<Self::Iter<'parse>, Reported> {
        let iter = match self.left.parse_iter(context, start) {
            Ok(iter) => Either::Left(iter),
            Err(Reported) => Either::Right(self.right.parse_iter(context, start)?),
        };
        Ok(EitherParseIter {
            start,
            parsers: self,
            iter,
        })
    }
}

impl<'parse, A, B> ParseIter<'parse> for EitherParseIter<'parse, A, B>
where
    A: Parser,
    B: Parser,
{
    type RawOutput = (Either<A::Output, B::Output>,);

    fn match_end(&self) -> usize {
        match &self.iter {
            Either::Left(iter) => iter.match_end(),
            Either::Right(iter) => iter.match_end(),
        }
    }

    fn backtrack(&mut self, context: &mut ParseContext<'parse>) -> Result<(), Reported> {
        match &mut self.iter {
            Either::Left(iter) => {
                if iter.backtrack(context).is_ok() {
                    return Ok(());
                }
                self.iter = Either::Right(self.parsers.right.parse_iter(context, self.start)?);
                Ok(())
            }
            Either::Right(iter) => iter.backtrack(context),
        }
    }

    fn convert(&self) -> (Either<A::Output, B::Output>,) {
        (match &self.iter {
            Either::Left(iter) => Either::Left(iter.convert().into_user_type()),
            Either::Right(iter) => Either::Right(iter.convert().into_user_type()),
        },)
    }
}

pub fn either<A, B>(left: A, right: B) -> EitherParser<A, B> {
    EitherParser { left, right }
}

pub type AltParser<A, B, T> =
    MapParser<EitherParser<A, B>, fn(Either<<A as Parser>::Output, <B as Parser>::Output>) -> T>;

/// Used by the `parser!()` macro to implement `{p1, p2, ...}` syntax.
#[doc(hidden)]
pub fn alt<A, B, T>(left: A, right: B) -> AltParser<A, B, T>
where
    A: Parser<Output = T>,
    B: Parser<Output = T>,
{
    map(either(left, right), |out| match out {
        Either::Left(value) => value,
        Either::Right(value) => value,
    })
}

pub type OptParser<P> = AltParser<P, EmptyParser, Option<<P as Parser>::Output>>;

/// Used by the `parser!()` macro to implement the `?` quantifier.
#[doc(hidden)]
pub fn opt<P>(pattern: P) -> OptParser<P>
where
    P: Parser,
{
    map(either(pattern, empty()), |e| match e {
        Either::Left(left) => Some(left),
        Either::Right(()) => None,
    })
}