use std::{
borrow::Cow,
error::Error,
fmt::{Display, Formatter},
};
use crate::{CreateParserState, ParseResult, ParseStatus, Parser};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ChoiceParserState<P1, P2> {
pub(crate) state1: ParseResult<P1>,
pub(crate) state2: ParseResult<P2>,
}
impl<P1, P2> ChoiceParserState<P1, P2> {
pub fn new(state1: P1, state2: P2) -> Self {
Self {
state1: Ok(state1),
state2: Ok(state2),
}
}
}
impl<P1: Default, P2: Default> Default for ChoiceParserState<P1, P2> {
fn default() -> Self {
ChoiceParserState {
state1: Ok(Default::default()),
state2: Ok(Default::default()),
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone, Default)]
pub struct ChoiceParser<P1, P2> {
pub(crate) parser1: P1,
pub(crate) parser2: P2,
}
impl<P1, P2> ChoiceParser<P1, P2> {
pub fn new(parser1: P1, parser2: P2) -> Self {
Self { parser1, parser2 }
}
}
impl<
O1,
O2,
PA1,
PA2,
P1: Parser<Output = O1, PartialState = PA1> + CreateParserState,
P2: Parser<Output = O2, PartialState = PA2> + CreateParserState,
> CreateParserState for ChoiceParser<P1, P2>
{
fn create_parser_state(&self) -> <Self as Parser>::PartialState {
ChoiceParserState {
state1: Ok(self.parser1.create_parser_state()),
state2: Ok(self.parser2.create_parser_state()),
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Either<L, R> {
Left(L),
Right(R),
}
impl<L: Display, R: Display> Display for Either<L, R> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Either::Left(l) => l.fmt(f),
Either::Right(r) => r.fmt(f),
}
}
}
impl<L: Error + 'static, R: Error + 'static> Error for Either<L, R> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Either::Left(l) => Some(l),
Either::Right(r) => Some(r),
}
}
}
impl<P1: Parser, P2: Parser> Parser for ChoiceParser<P1, P2> {
type Output = Either<P1::Output, P2::Output>;
type PartialState = ChoiceParserState<P1::PartialState, P2::PartialState>;
fn parse<'a>(
&self,
state: &Self::PartialState,
input: &'a [u8],
) -> crate::ParseResult<ParseStatus<'a, Self::PartialState, Self::Output>> {
match (&state.state1, &state.state2) {
(Ok(p1), Ok(p2)) => {
match (self.parser1.parse(p1, input), self.parser2.parse(p2, input)) {
(Ok(ParseStatus::Finished { result, remaining }), _) => {
Ok(ParseStatus::Finished {
result: Either::Left(result),
remaining,
})
}
(_, Ok(ParseStatus::Finished { result, remaining })) => {
Ok(ParseStatus::Finished {
result: Either::Right(result),
remaining,
})
}
(
Ok(ParseStatus::Incomplete {
new_state: p1,
required_next: required_next1,
}),
Ok(ParseStatus::Incomplete {
new_state: p2,
required_next: required_next2,
}),
) => {
let new_state = ChoiceParserState {
state1: Ok(p1),
state2: Ok(p2),
};
let mut common_bytes = 0;
for (byte1, byte2) in required_next1.bytes().zip(required_next2.bytes()) {
if byte1 != byte2 {
break;
}
common_bytes += 1;
}
Ok(ParseStatus::Incomplete {
new_state,
required_next: match (required_next1, required_next2) {
(Cow::Borrowed(required_next), _) => {
Cow::Borrowed(&required_next[..common_bytes])
}
(_, Cow::Borrowed(required_next)) => {
Cow::Borrowed(&required_next[..common_bytes])
}
(Cow::Owned(mut required_next), _) => {
required_next.truncate(common_bytes);
Cow::Owned(required_next)
}
},
})
}
(
Ok(ParseStatus::Incomplete {
new_state: p1,
required_next,
}),
Err(err2),
) => {
let new_state = ChoiceParserState {
state1: Ok(p1),
state2: Err(err2),
};
Ok(ParseStatus::Incomplete {
new_state,
required_next,
})
}
(
Err(err1),
Ok(ParseStatus::Incomplete {
new_state: p2,
required_next,
}),
) => {
let new_state = ChoiceParserState {
state1: Err(err1),
state2: Ok(p2),
};
Ok(ParseStatus::Incomplete {
new_state,
required_next,
})
}
(Err(err1), Err(_)) => Err(err1),
}
}
(Ok(p1), Err(err2)) => {
let result = self.parser1.parse(p1, input)?;
match result {
ParseStatus::Finished { result, remaining } => Ok(ParseStatus::Finished {
result: Either::Left(result),
remaining,
}),
ParseStatus::Incomplete {
new_state: p1,
required_next,
} => {
let new_state = ChoiceParserState {
state1: Ok(p1),
state2: Err(err2.clone()),
};
Ok(ParseStatus::Incomplete {
new_state,
required_next,
})
}
}
}
(Err(err1), Ok(p2)) => {
let result = self.parser2.parse(p2, input)?;
match result {
ParseStatus::Finished { result, remaining } => Ok(ParseStatus::Finished {
result: Either::Right(result),
remaining,
}),
ParseStatus::Incomplete {
new_state: p2,
required_next,
} => {
let new_state = ChoiceParserState {
state1: Err(err1.clone()),
state2: Ok(p2),
};
Ok(ParseStatus::Incomplete {
new_state,
required_next,
})
}
}
}
(Err(_), Err(_)) => {
unreachable!()
}
}
}
}
#[test]
fn choice_parser() {
use crate::{LiteralParser, LiteralParserOffset};
let parser = ChoiceParser {
parser1: LiteralParser::new("Hello, "),
parser2: LiteralParser::new("world!"),
};
let state = ChoiceParserState::default();
assert_eq!(
parser.parse(&state, b"Hello, ").unwrap(),
ParseStatus::Finished {
result: Either::Left(()),
remaining: &[]
}
);
assert_eq!(
parser.parse(&state, b"Hello, ").unwrap(),
ParseStatus::Finished {
result: Either::Left(()),
remaining: &[]
}
);
assert_eq!(
parser.parse(&state, b"world!").unwrap(),
ParseStatus::Finished {
result: Either::Right(()),
remaining: &[]
}
);
assert!(parser.parse(&state, b"Goodbye, world!").is_err());
let parser = ChoiceParser::new(
LiteralParser::new("This isn't a test"),
LiteralParser::new("This is a test"),
);
let state = ChoiceParserState::default();
assert!(matches!(
parser.parse(&state, b"This isn").unwrap(),
ParseStatus::Incomplete {
new_state: ChoiceParserState {
state1: Ok(LiteralParserOffset { offset: 8 }),
state2: Err(_),
},
required_next: Cow::Borrowed("'t a test")
},
));
let parser = ChoiceParser::new(
LiteralParser::new("Hello world"),
LiteralParser::new("Hi world"),
);
let state = ChoiceParserState::default();
assert!(matches!(
parser.parse(&state, b"H").unwrap(),
ParseStatus::Incomplete {
new_state: ChoiceParserState {
state1: Ok(LiteralParserOffset { offset: 1 }),
state2: Ok(LiteralParserOffset { offset: 1 }),
},
required_next: Cow::Borrowed("")
},
));
}