use nom::error::{Error, ErrorKind};
use nom::error::{ParseError, VerboseError};
pub trait TagError<I, T>: Sized {
fn from_tag(input: I, tag: T) -> Self;
fn from_tag_no_case(input: I, tag: T) -> Self {
Self::from_tag(input, tag)
}
}
impl<I, T> TagError<I, T> for () {
fn from_tag(_input: I, _tag: T) {}
}
impl<I, T> TagError<I, T> for (I, ErrorKind) {
fn from_tag(input: I, _tag: T) -> Self {
(input, ErrorKind::Tag)
}
}
impl<I, T> TagError<I, T> for Error<I> {
fn from_tag(input: I, _tag: T) -> Self {
Error::new(input, ErrorKind::Tag)
}
}
impl<I, T> TagError<I, T> for VerboseError<I> {
fn from_tag(input: I, _tag: T) -> Self {
VerboseError::from_error_kind(input, ErrorKind::Tag)
}
}
pub mod complete {
use nom::{Compare, CompareResult, Err, IResult, InputLength, InputTake};
use super::TagError;
pub fn tag<T, I, E>(tag: T) -> impl Clone + Fn(I) -> IResult<I, I, E>
where
T: InputLength + Clone,
I: InputTake + Compare<T>,
E: TagError<I, T>,
{
let tag_len = tag.input_len();
move |input: I| match input.compare(tag.clone()) {
CompareResult::Ok => Ok(input.take_split(tag_len)),
_ => Err(Err::Error(E::from_tag(input, tag.clone()))),
}
}
pub fn tag_no_case<T, I, E>(tag: T) -> impl Clone + Fn(I) -> IResult<I, I, E>
where
T: InputLength + Clone,
I: InputTake + Compare<T>,
E: TagError<I, T>,
{
move |input: I| match input.compare_no_case(tag.clone()) {
CompareResult::Ok => Ok(input.take_split(tag.input_len())),
_ => Err(Err::Error(E::from_tag_no_case(input, tag.clone()))),
}
}
}
pub mod streaming {
use nom::{Compare, CompareResult, Err, IResult, InputLength, InputTake, Needed};
use super::TagError;
pub fn tag<T, I, E>(tag: T) -> impl Clone + Fn(I) -> IResult<I, I, E>
where
T: InputLength + Clone,
I: InputLength + InputTake + Compare<T>,
E: TagError<I, T>,
{
let tag_len = tag.input_len();
move |input: I| match input.compare(tag.clone()) {
CompareResult::Ok => Ok(input.take_split(tag_len)),
CompareResult::Incomplete => {
Err(Err::Incomplete(Needed::new(tag_len - input.input_len())))
}
CompareResult::Error => Err(Err::Error(E::from_tag(input, tag.clone()))),
}
}
pub fn tag_no_case<T, I, E>(tag: T) -> impl Clone + Fn(I) -> IResult<I, I, E>
where
T: InputLength + Clone,
I: InputLength + InputTake + Compare<T>,
E: TagError<I, T>,
{
let tag_len = tag.input_len();
move |input: I| match input.compare_no_case(tag.clone()) {
CompareResult::Ok => Ok(input.take_split(tag_len)),
CompareResult::Incomplete => {
Err(Err::Incomplete(Needed::new(tag_len - input.input_len())))
}
CompareResult::Error => Err(Err::Error(E::from_tag_no_case(input, tag.clone()))),
}
}
}