use core::marker::PhantomData;
use crate::error::ErrorKind;
use crate::FindToken;
use crate::IsStreaming;
use crate::Mode;
use crate::{error::ParseError, AsChar, Err, IResult, Input, Needed, Parser};
#[cfg(test)]
mod tests;
pub mod complete;
pub mod streaming;
#[inline]
#[doc(hidden)]
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_alpha`")]
pub fn is_alphabetic(chr: u8) -> bool {
matches!(chr, 0x41..=0x5A | 0x61..=0x7A)
}
#[inline]
#[doc(hidden)]
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_dec_digit`")]
pub fn is_digit(chr: u8) -> bool {
matches!(chr, 0x30..=0x39)
}
#[inline]
#[doc(hidden)]
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_hex_digit`")]
pub fn is_hex_digit(chr: u8) -> bool {
matches!(chr, 0x30..=0x39 | 0x41..=0x46 | 0x61..=0x66)
}
#[inline]
#[doc(hidden)]
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_oct_digit`")]
pub fn is_oct_digit(chr: u8) -> bool {
matches!(chr, 0x30..=0x37)
}
#[inline]
pub fn is_bin_digit(chr: u8) -> bool {
matches!(chr, 0x30..=0x31)
}
#[inline]
#[doc(hidden)]
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_alphanum`")]
pub fn is_alphanumeric(chr: u8) -> bool {
AsChar::is_alphanum(chr)
}
#[inline]
#[doc(hidden)]
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_space`")]
pub fn is_space(chr: u8) -> bool {
chr == b' ' || chr == b'\t'
}
#[inline]
#[doc(hidden)]
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_newline`")]
pub fn is_newline(chr: u8) -> bool {
chr == b'\n'
}
pub fn char<I, Error: ParseError<I>>(c: char) -> impl Parser<I, Output = char, Error = Error>
where
I: Input,
<I as Input>::Item: AsChar,
{
Char { c, e: PhantomData }
}
pub struct Char<E> {
c: char,
e: PhantomData<E>,
}
impl<I, Error: ParseError<I>> Parser<I> for Char<Error>
where
I: Input,
<I as Input>::Item: AsChar,
{
type Output = char;
type Error = Error;
#[inline(always)]
fn process<OM: crate::OutputMode>(
&mut self,
i: I,
) -> crate::PResult<OM, I, Self::Output, Self::Error> {
match (i).iter_elements().next().map(|t| {
let b = t.as_char() == self.c;
(&self.c, b)
}) {
None => {
if OM::Incomplete::is_streaming() {
Err(Err::Incomplete(Needed::new(self.c.len() - i.input_len())))
} else {
Err(Err::Error(OM::Error::bind(|| Error::from_char(i, self.c))))
}
}
Some((_, false)) => Err(Err::Error(OM::Error::bind(|| Error::from_char(i, self.c)))),
Some((c, true)) => Ok((i.take_from(c.len()), OM::Output::bind(|| c.as_char()))),
}
}
}
pub fn satisfy<F, I, Error: ParseError<I>>(
predicate: F,
) -> impl Parser<I, Output = char, Error = Error>
where
I: Input,
<I as Input>::Item: AsChar,
F: Fn(char) -> bool,
{
Satisfy {
predicate,
make_error: |i: I| Error::from_error_kind(i, ErrorKind::Satisfy),
}
}
pub struct Satisfy<F, MakeError> {
predicate: F,
make_error: MakeError,
}
impl<I, Error: ParseError<I>, F, MakeError> Parser<I> for Satisfy<F, MakeError>
where
I: Input,
<I as Input>::Item: AsChar,
F: Fn(char) -> bool,
MakeError: Fn(I) -> Error,
{
type Output = char;
type Error = Error;
#[inline(always)]
fn process<OM: crate::OutputMode>(
&mut self,
i: I,
) -> crate::PResult<OM, I, Self::Output, Self::Error> {
match (i).iter_elements().next().map(|t| {
let c = t.as_char();
let b = (self.predicate)(c);
(c, b)
}) {
None => {
if OM::Incomplete::is_streaming() {
Err(Err::Incomplete(Needed::Unknown))
} else {
Err(Err::Error(OM::Error::bind(|| (self.make_error)(i))))
}
}
Some((_, false)) => Err(Err::Error(OM::Error::bind(|| (self.make_error)(i)))),
Some((c, true)) => Ok((i.take_from(c.len()), OM::Output::bind(|| c.as_char()))),
}
}
}
pub fn one_of<I, T, Error: ParseError<I>>(list: T) -> impl Parser<I, Output = char, Error = Error>
where
I: Input,
<I as Input>::Item: AsChar,
T: FindToken<char>,
{
Satisfy {
predicate: move |c: char| list.find_token(c),
make_error: move |i| Error::from_error_kind(i, ErrorKind::OneOf),
}
}
pub fn none_of<I, T, Error: ParseError<I>>(list: T) -> impl Parser<I, Output = char, Error = Error>
where
I: Input,
<I as Input>::Item: AsChar,
T: FindToken<char>,
{
Satisfy {
predicate: move |c: char| !list.find_token(c),
make_error: move |i| Error::from_error_kind(i, ErrorKind::NoneOf),
}
}
pub fn anychar<T, E: ParseError<T>>(input: T) -> IResult<T, char, E>
where
T: Input,
<T as Input>::Item: AsChar,
{
let mut it = input.iter_elements();
match it.next() {
None => Err(Err::Error(E::from_error_kind(input, ErrorKind::Eof))),
Some(c) => Ok((input.take_from(c.len()), c.as_char())),
}
}
pub struct AnyChar<E> {
e: PhantomData<E>,
}
impl<I, Error: ParseError<I>> Parser<I> for AnyChar<Error>
where
I: Input,
<I as Input>::Item: AsChar,
{
type Output = char;
type Error = Error;
fn process<OM: crate::OutputMode>(
&mut self,
i: I,
) -> crate::PResult<OM, I, Self::Output, Self::Error> {
match (i).iter_elements().next() {
None => {
if OM::Incomplete::is_streaming() {
Err(Err::Incomplete(Needed::new(1)))
} else {
Err(Err::Error(OM::Error::bind(|| {
Error::from_error_kind(i, ErrorKind::Eof)
})))
}
}
Some(c) => Ok((i.take_from(c.len()), OM::Output::bind(|| c.as_char()))),
}
}
}
pub fn digit1<T, E: ParseError<T>>() -> impl Parser<T, Output = T, Error = E>
where
T: Input,
<T as Input>::Item: AsChar,
{
Digit1 { e: PhantomData }
}
pub struct Digit1<E> {
e: PhantomData<E>,
}
impl<I: Input, E: ParseError<I>> Parser<I> for Digit1<E>
where
<I as Input>::Item: AsChar,
{
type Output = I;
type Error = E;
#[inline]
fn process<OM: crate::OutputMode>(
&mut self,
input: I,
) -> crate::PResult<OM, I, Self::Output, Self::Error> {
input.split_at_position_mode1::<OM, _, _>(|item| !item.is_dec_digit(), ErrorKind::Digit)
}
}
pub fn multispace0<T, E: ParseError<T>>() -> impl Parser<T, Output = T, Error = E>
where
T: Input,
<T as Input>::Item: AsChar,
{
MultiSpace0 { e: PhantomData }
}
pub struct MultiSpace0<E> {
e: PhantomData<E>,
}
impl<I, Error: ParseError<I>> Parser<I> for MultiSpace0<Error>
where
I: Input,
<I as Input>::Item: AsChar,
{
type Output = I;
type Error = Error;
fn process<OM: crate::OutputMode>(
&mut self,
i: I,
) -> crate::PResult<OM, I, Self::Output, Self::Error> {
i.split_at_position_mode::<OM, _, _>(|item| {
let c = item.as_char();
!(c == ' ' || c == '\t' || c == '\r' || c == '\n')
})
}
}