use std::ops::{RangeFrom, RangeTo};
use nom::{
character::streaming::satisfy,
combinator::{opt, recognize},
error::ParseError,
multi::many0_count,
sequence::{pair, terminated},
AsChar, Err as OutCome, IResult, InputIter, InputLength, Needed, Offset, Slice,
};
use crate::{
is_alpha, is_bit, is_char, is_cr, is_ctl, is_digit, is_dquote, is_hexdig, is_htab, is_lf,
is_sp, is_wsp,
};
pub fn alpha<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_alpha)(input)
}
pub fn bit<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_bit)(input)
}
pub fn char<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_char)(input)
}
pub fn cr<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_cr)(input)
}
pub fn crlf<I, E>(input: I) -> IResult<I, (char, char), E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
pair(satisfy(is_cr), satisfy(is_lf))(input)
}
pub fn crlf_relaxed<I, E>(input: I) -> IResult<I, (Option<char>, char), E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
pair(opt(satisfy(is_cr)), satisfy(is_lf))(input)
}
pub fn ctl<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_ctl)(input)
}
pub fn digit<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_digit)(input)
}
pub fn dquote<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_dquote)(input)
}
pub fn hexdig<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_hexdig)(input)
}
pub fn htab<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_htab)(input)
}
pub fn lf<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_lf)(input)
}
pub fn lwsp<I, E>(input: I) -> IResult<I, I, E>
where
I: Clone
+ Offset
+ PartialEq
+ InputLength
+ InputIter
+ Slice<RangeTo<usize>>
+ Slice<RangeFrom<usize>>,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
recognize(many0_count(terminated(opt(crlf), wsp)))(input)
}
pub fn octet<E>(input: &[u8]) -> IResult<&[u8], u8, E>
where
for<'a> E: ParseError<&'a [u8]>,
{
match input.split_first() {
None => Err(OutCome::Incomplete(Needed::new(1))),
Some((&b, tail)) => Ok((tail, b)),
}
}
pub fn sp<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_sp)(input)
}
pub fn vchar<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_char)(input)
}
pub fn wsp<I, E>(input: I) -> IResult<I, char, E>
where
I: InputLength + InputIter + Slice<RangeFrom<usize>> + Clone,
<I as InputIter>::Item: AsChar,
E: ParseError<I>,
{
satisfy(is_wsp)(input)
}
#[cfg(test)]
mod tests {
use nom::error::VerboseError;
use super::*;
#[test]
fn test_cr() {
assert!(cr::<_, VerboseError<_>>("\n").is_err());
assert_eq!(cr::<_, VerboseError<_>>("\r"), Ok(("", '\r')));
assert!(cr::<_, VerboseError<_>>(&b"\n"[..]).is_err());
assert_eq!(cr::<_, VerboseError<_>>(&b"\r"[..]), Ok((&b""[..], '\r')));
}
}