use crate::combinator::impls;
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
use crate::error::FromRecoverableError;
use crate::error::{AddContext, FromExternalError, ParseError, ParserError, Result};
use crate::stream::{Compare, Location, ParseSlice, Stream, StreamIsPartial};
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
use crate::stream::{Recover, Recoverable};
pub trait Parser<I, O, E> {
#[inline]
fn parse(&mut self, mut input: I) -> Result<O, ParseError<I, <E as ParserError<I>>::Inner>>
where
Self: core::marker::Sized,
I: Stream,
I: StreamIsPartial,
E: ParserError<I>,
<E as ParserError<I>>::Inner: ParserError<I>,
{
debug_assert!(
!I::is_partial_supported(),
"partial streams need to handle `ErrMode::Incomplete`"
);
let start = input.checkpoint();
let (o, _) = (self.by_ref(), crate::combinator::eof)
.parse_next(&mut input)
.map_err(|e| {
let e = e.into_inner().unwrap_or_else(|_err| {
panic!("complete parsers should not report `ErrMode::Incomplete(_)`")
});
ParseError::new(input, start, e)
})?;
Ok(o)
}
#[inline]
fn parse_iter(&mut self, input: I) -> impls::ParseIter<'_, Self, I, O, E>
where
Self: core::marker::Sized,
I: Stream,
I: StreamIsPartial,
E: ParserError<I>,
<E as ParserError<I>>::Inner: ParserError<I>,
{
debug_assert!(
!I::is_partial_supported(),
"partial streams need to handle `ErrMode::Incomplete`"
);
let start = input.checkpoint();
impls::ParseIter {
parser: self,
input: Some(input),
start: Some(start),
marker: Default::default(),
}
}
fn parse_next(&mut self, input: &mut I) -> Result<O, E>;
#[inline(always)]
fn parse_peek(&mut self, mut input: I) -> Result<(I, O), E> {
match self.parse_next(&mut input) {
Ok(o) => Ok((input, o)),
Err(err) => Err(err),
}
}
#[inline(always)]
fn by_ref(&mut self) -> impls::ByRef<'_, Self, I, O, E>
where
Self: core::marker::Sized,
{
impls::ByRef {
p: self,
marker: Default::default(),
}
}
#[doc(alias = "to")]
#[inline(always)]
fn value<O2>(self, val: O2) -> impls::Value<Self, I, O, O2, E>
where
Self: core::marker::Sized,
O2: Clone,
{
impls::Value {
parser: self,
val,
marker: Default::default(),
}
}
#[inline(always)]
fn default_value<O2>(self) -> impls::DefaultValue<Self, I, O, O2, E>
where
Self: core::marker::Sized,
O2: core::default::Default,
{
impls::DefaultValue {
parser: self,
marker: Default::default(),
}
}
#[inline(always)]
fn void(self) -> impls::Void<Self, I, O, E>
where
Self: core::marker::Sized,
{
impls::Void {
parser: self,
marker: Default::default(),
}
}
#[inline(always)]
fn output_into<O2>(self) -> impls::OutputInto<Self, I, O, O2, E>
where
Self: core::marker::Sized,
O: Into<O2>,
{
impls::OutputInto {
parser: self,
marker: Default::default(),
}
}
#[doc(alias = "concat")]
#[doc(alias = "recognize")]
#[inline(always)]
fn take(self) -> impls::Take<Self, I, O, E>
where
Self: core::marker::Sized,
I: Stream,
{
impls::Take {
parser: self,
marker: Default::default(),
}
}
#[doc(alias = "consumed")]
#[doc(alias = "with_recognized")]
#[inline(always)]
fn with_taken(self) -> impls::WithTaken<Self, I, O, E>
where
Self: core::marker::Sized,
I: Stream,
{
impls::WithTaken {
parser: self,
marker: Default::default(),
}
}
#[inline(always)]
fn span(self) -> impls::Span<Self, I, O, E>
where
Self: core::marker::Sized,
I: Stream + Location,
{
impls::Span {
parser: self,
marker: Default::default(),
}
}
#[inline(always)]
fn with_span(self) -> impls::WithSpan<Self, I, O, E>
where
Self: core::marker::Sized,
I: Stream + Location,
{
impls::WithSpan {
parser: self,
marker: Default::default(),
}
}
#[inline(always)]
fn map<G, O2>(self, map: G) -> impls::Map<Self, G, I, O, O2, E>
where
G: FnMut(O) -> O2,
Self: core::marker::Sized,
{
impls::Map {
parser: self,
map,
marker: Default::default(),
}
}
#[inline(always)]
fn try_map<G, O2, E2>(self, map: G) -> impls::TryMap<Self, G, I, O, O2, E, E2>
where
Self: core::marker::Sized,
G: FnMut(O) -> Result<O2, E2>,
I: Stream,
E: FromExternalError<I, E2>,
E: ParserError<I>,
{
impls::TryMap {
parser: self,
map,
marker: Default::default(),
}
}
#[doc(alias = "satisfy_map")]
#[doc(alias = "filter_map")]
#[doc(alias = "map_opt")]
#[inline(always)]
fn verify_map<G, O2>(self, map: G) -> impls::VerifyMap<Self, G, I, O, O2, E>
where
Self: core::marker::Sized,
G: FnMut(O) -> Option<O2>,
I: Stream,
E: ParserError<I>,
{
impls::VerifyMap {
parser: self,
map,
marker: Default::default(),
}
}
#[inline(always)]
fn flat_map<G, H, O2>(self, map: G) -> impls::FlatMap<Self, G, H, I, O, O2, E>
where
Self: core::marker::Sized,
G: FnMut(O) -> H,
H: Parser<I, O2, E>,
{
impls::FlatMap {
f: self,
g: map,
marker: Default::default(),
}
}
#[inline(always)]
fn and_then<G, O2>(self, inner: G) -> impls::AndThen<Self, G, I, O, O2, E>
where
Self: core::marker::Sized,
G: Parser<O, O2, E>,
O: StreamIsPartial,
I: Stream,
{
impls::AndThen {
outer: self,
inner,
marker: Default::default(),
}
}
#[doc(alias = "from_str")]
#[inline(always)]
fn parse_to<O2>(self) -> impls::ParseTo<Self, I, O, O2, E>
where
Self: core::marker::Sized,
I: Stream,
O: ParseSlice<O2>,
E: ParserError<I>,
{
impls::ParseTo {
p: self,
marker: Default::default(),
}
}
#[doc(alias = "satisfy")]
#[doc(alias = "filter")]
#[inline(always)]
fn verify<G, O2>(self, filter: G) -> impls::Verify<Self, G, I, O, O2, E>
where
Self: core::marker::Sized,
G: FnMut(&O2) -> bool,
I: Stream,
O: core::borrow::Borrow<O2>,
O2: ?Sized,
E: ParserError<I>,
{
impls::Verify {
parser: self,
filter,
marker: Default::default(),
}
}
#[doc(alias = "labelled")]
#[inline(always)]
fn context<C>(self, context: C) -> impls::Context<Self, I, O, E, C>
where
Self: core::marker::Sized,
I: Stream,
E: AddContext<I, C>,
E: ParserError<I>,
C: Clone + core::fmt::Debug,
{
impls::Context {
parser: self,
context,
marker: Default::default(),
}
}
#[doc(alias = "labelled")]
#[inline(always)]
fn context_with<F, C, FI>(self, context: F) -> impls::ContextWith<Self, I, O, E, F, C, FI>
where
Self: core::marker::Sized,
I: Stream,
E: AddContext<I, C>,
E: ParserError<I>,
F: Fn() -> FI + Clone,
C: core::fmt::Debug,
FI: Iterator<Item = C>,
{
impls::ContextWith {
parser: self,
context,
marker: Default::default(),
}
}
#[inline(always)]
fn map_err<G, E2>(self, map: G) -> impls::MapErr<Self, G, I, O, E, E2>
where
G: FnMut(E) -> E2,
Self: core::marker::Sized,
{
impls::MapErr {
parser: self,
map,
marker: Default::default(),
}
}
#[inline(always)]
fn complete_err(self) -> impls::CompleteErr<Self, I, O, E>
where
Self: core::marker::Sized,
{
impls::CompleteErr {
p: self,
marker: Default::default(),
}
}
#[inline(always)]
fn err_into<E2>(self) -> impls::ErrInto<Self, I, O, E, E2>
where
Self: core::marker::Sized,
E: Into<E2>,
{
impls::ErrInto {
parser: self,
marker: Default::default(),
}
}
#[inline(always)]
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
fn retry_after<R>(self, recover: R) -> impls::RetryAfter<Self, R, I, O, E>
where
Self: core::marker::Sized,
R: Parser<I, (), E>,
I: Stream,
I: Recover<E>,
E: ParserError<I> + FromRecoverableError<I, E>,
{
impls::RetryAfter {
parser: self,
recover,
marker: Default::default(),
}
}
#[inline(always)]
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
fn resume_after<R>(self, recover: R) -> impls::ResumeAfter<Self, R, I, O, E>
where
Self: core::marker::Sized,
R: Parser<I, (), E>,
I: Stream,
I: Recover<E>,
E: ParserError<I> + FromRecoverableError<I, E>,
{
impls::ResumeAfter {
parser: self,
recover,
marker: Default::default(),
}
}
}
impl<I, O, E, F> Parser<I, O, E> for F
where
F: FnMut(&mut I) -> Result<O, E>,
I: Stream,
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<O, E> {
self(i)
}
}
impl<I, E> Parser<I, u8, E> for u8
where
I: StreamIsPartial,
I: Stream,
I: Compare<u8>,
E: ParserError<I>,
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<u8, E> {
crate::token::literal(*self).value(*self).parse_next(i)
}
}
impl<I, E> Parser<I, char, E> for char
where
I: StreamIsPartial,
I: Stream,
I: Compare<char>,
E: ParserError<I>,
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<char, E> {
crate::token::literal(*self).value(*self).parse_next(i)
}
}
impl<'s, I, E: ParserError<I>> Parser<I, <I as Stream>::Slice, E> for &'s [u8]
where
I: Compare<&'s [u8]> + StreamIsPartial,
I: Stream,
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<<I as Stream>::Slice, E> {
crate::token::literal(*self).parse_next(i)
}
}
impl<'s, I, E: ParserError<I>, const N: usize> Parser<I, <I as Stream>::Slice, E> for &'s [u8; N]
where
I: Compare<&'s [u8; N]> + StreamIsPartial,
I: Stream,
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<<I as Stream>::Slice, E> {
crate::token::literal(*self).parse_next(i)
}
}
impl<'s, I, E: ParserError<I>> Parser<I, <I as Stream>::Slice, E> for &'s str
where
I: Compare<&'s str> + StreamIsPartial,
I: Stream,
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<<I as Stream>::Slice, E> {
crate::token::literal(*self).parse_next(i)
}
}
impl<I: Stream, E: ParserError<I>> Parser<I, (), E> for () {
#[inline(always)]
fn parse_next(&mut self, _i: &mut I) -> Result<(), E> {
Ok(())
}
}
macro_rules! impl_parser_for_tuple {
($($index:tt $parser:ident $output:ident),+) => (
#[allow(non_snake_case)]
impl<I: Stream, $($output),+, E: ParserError<I>, $($parser),+> Parser<I, ($($output),+,), E> for ($($parser),+,)
where
$($parser: Parser<I, $output, E>),+
{
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<($($output),+,), E> {
$(let $output = self.$index.parse_next(i)?;)+
Ok(($($output),+,))
}
}
)
}
macro_rules! impl_parser_for_tuples {
($index1:tt $parser1:ident $output1:ident, $($index:tt $parser:ident $output:ident),+) => {
impl_parser_for_tuples!(__impl $index1 $parser1 $output1; $($index $parser $output),+);
};
(__impl $($index:tt $parser:ident $output:ident),+; $index1:tt $parser1:ident $output1:ident $(,$index2:tt $parser2:ident $output2:ident)*) => {
impl_parser_for_tuple!($($index $parser $output),+);
impl_parser_for_tuples!(__impl $($index $parser $output),+, $index1 $parser1 $output1; $($index2 $parser2 $output2),*);
};
(__impl $($index:tt $parser:ident $output:ident),+;) => {
impl_parser_for_tuple!($($index $parser $output),+);
}
}
impl_parser_for_tuples!(
0 P0 O0,
1 P1 O1,
2 P2 O2,
3 P3 O3,
4 P4 O4,
5 P5 O5,
6 P6 O6,
7 P7 O7,
8 P8 O8,
9 P9 O9,
10 P10 O10
);
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
impl<I, O, E> Parser<I, O, E> for Box<dyn Parser<I, O, E> + '_> {
#[inline(always)]
fn parse_next(&mut self, i: &mut I) -> Result<O, E> {
(**self).parse_next(i)
}
}
pub trait ModalParser<I, O, E>: Parser<I, O, crate::error::ErrMode<E>> {}
impl<I, O, E, P> ModalParser<I, O, E> for P where P: Parser<I, O, crate::error::ErrMode<E>> {}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
pub trait RecoverableParser<I, O, R, E> {
fn recoverable_parse(&mut self, input: I) -> (I, Option<O>, Vec<R>);
}
#[cfg(feature = "unstable-recover")]
#[cfg(feature = "std")]
impl<P, I, O, R, E> RecoverableParser<I, O, R, E> for P
where
P: Parser<Recoverable<I, R>, O, E>,
I: Stream,
I: StreamIsPartial,
R: FromRecoverableError<Recoverable<I, R>, E>,
R: core::fmt::Debug,
E: FromRecoverableError<Recoverable<I, R>, E>,
E: ParserError<Recoverable<I, R>>,
E: core::fmt::Debug,
{
fn recoverable_parse(&mut self, input: I) -> (I, Option<O>, Vec<R>) {
debug_assert!(
!I::is_partial_supported(),
"partial streams need to handle `ErrMode::Incomplete`"
);
let start = input.checkpoint();
let mut input = Recoverable::new(input);
let start_token = input.checkpoint();
let result = (
self.by_ref(),
crate::combinator::eof.resume_after(crate::token::rest.void()),
)
.parse_next(&mut input);
let (o, err) = match result {
Ok((o, _)) => (Some(o), None),
Err(err) => {
let err_start = input.checkpoint();
let err = R::from_recoverable_error(&start_token, &err_start, &input, err);
(None, Some(err))
}
};
let (mut input, mut errs) = input.into_parts();
input.reset(&start);
if let Some(err) = err {
errs.push(err);
}
(input, o, errs)
}
}
#[cfg(all(test, feature = "ascii", feature = "binary"))]
mod tests {
use super::*;
use snapbox::prelude::*;
use snapbox::str;
use crate::binary::be_u16;
use crate::error::ErrMode;
use crate::error::Needed;
use crate::error::TestResult;
use crate::token::take;
use crate::Partial;
#[doc(hidden)]
#[macro_export]
macro_rules! assert_size (
($t:ty, $sz:expr) => (
assert!(core::mem::size_of::<$t>() <= $sz, "{} <= {} failed", core::mem::size_of::<$t>(), $sz);
);
);
#[test]
#[cfg(target_pointer_width = "64")]
fn size_test() {
assert_size!(Result<&[u8], (&[u8], u32)>, 40);
assert_size!(Result<&str, u32>, 40);
assert_size!(Needed, 8);
assert_size!(ErrMode<u32>, 16);
}
#[test]
fn err_map_test() {
let e = ErrMode::Backtrack(1);
assert_eq!(e.map(|v| v + 1), ErrMode::Backtrack(2));
}
#[test]
fn single_element_tuples() {
use crate::ascii::alpha1;
let mut parser = (alpha1,);
assert_parse!(
parser.parse_peek("abc123def"),
str![[r#"
Ok(
(
"123def",
(
"abc",
),
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("123def"),
str![[r#"
Err(
Backtrack(
InputError {
input: "123def",
},
),
)
"#]]
.raw()
);
}
#[test]
fn tuple_test() {
#[allow(clippy::type_complexity)]
fn tuple_3<'i>(
i: &mut Partial<&'i [u8]>,
) -> TestResult<Partial<&'i [u8]>, (u16, &'i [u8], &'i [u8])> {
(be_u16, take(3u8), "fg").parse_next(i)
}
assert_parse!(
tuple_3.parse_peek(Partial::new(&b"abcdefgh"[..])),
str![[r#"
Ok(
(
Partial {
input: [
104,
],
partial: true,
},
(
24930,
[
99,
100,
101,
],
[
102,
103,
],
),
),
)
"#]]
.raw()
);
assert_parse!(
tuple_3.parse_peek(Partial::new(&b"abcd"[..])),
str![[r#"
Err(
Incomplete(
Size(
1,
),
),
)
"#]]
.raw()
);
assert_parse!(
tuple_3.parse_peek(Partial::new(&b"abcde"[..])),
str![[r#"
Err(
Incomplete(
Unknown,
),
)
"#]]
.raw()
);
assert_parse!(
tuple_3.parse_peek(Partial::new(&b"abcdejk"[..])),
str![[r#"
Err(
Backtrack(
InputError {
input: Partial {
input: [
106,
107,
],
partial: true,
},
},
),
)
"#]]
.raw()
);
}
#[test]
fn unit_type() {
fn parser<'i>(i: &mut &'i str) -> TestResult<&'i str, ()> {
().parse_next(i)
}
assert_parse!(
parser.parse_peek("abxsbsh"),
str![[r#"
Ok(
(
"abxsbsh",
(),
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek("sdfjakdsas"),
str![[r#"
Ok(
(
"sdfjakdsas",
(),
),
)
"#]]
.raw()
);
assert_parse!(
parser.parse_peek(""),
str![[r#"
Ok(
(
"",
(),
),
)
"#]]
.raw()
);
}
}