use nom::error::{ErrorKind, ParseError};
use nom::{
AsBytes, Compare, CompareResult, Err, IResult, InputIter, InputLength, InputTake,
InputTakeAtPosition, Needed, Offset, ParseTo, Slice,
};
use std::num::NonZero;
use std::str::{CharIndices, Chars};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ParsingContext<'a> {
input: &'a str,
namespace: &'a str,
}
impl<'a> ParsingContext<'a> {
pub fn new(input: &'a str, namespace: &'a str) -> Self {
Self { input, namespace }
}
pub fn into_inner(self) -> &'a str {
self.input
}
}
impl AsBytes for ParsingContext<'_> {
fn as_bytes(&self) -> &[u8] {
self.input.as_bytes()
}
}
impl<'a, T> Compare<T> for ParsingContext<'a>
where
&'a str: Compare<T>,
{
fn compare(&self, t: T) -> CompareResult {
self.input.compare(t)
}
fn compare_no_case(&self, t: T) -> CompareResult {
self.input.compare_no_case(t)
}
}
impl<'a> InputIter for ParsingContext<'a> {
type Item = char;
type Iter = CharIndices<'a>;
type IterElem = Chars<'a>;
fn iter_indices(&self) -> Self::Iter {
self.input.char_indices()
}
fn iter_elements(&self) -> Self::IterElem {
self.input.chars()
}
fn position<P>(&self, predicate: P) -> Option<usize>
where
P: Fn(Self::Item) -> bool,
{
self.input.position(predicate)
}
fn slice_index(&self, count: usize) -> Result<usize, Needed> {
self.input.slice_index(count)
}
}
impl InputLength for ParsingContext<'_> {
fn input_len(&self) -> usize {
self.input.len()
}
}
impl InputTake for ParsingContext<'_> {
fn take(&self, count: usize) -> Self {
Self::new(&self.input[..count], self.namespace)
}
fn take_split(&self, count: usize) -> (Self, Self) {
let (s0, s1) = self.input.split_at(count);
(ParsingContext::new(s1, self.namespace), ParsingContext::new(s0, self.namespace))
}
}
impl<'a, R> Slice<R> for ParsingContext<'a>
where
&'a str: Slice<R>,
{
fn slice(&self, range: R) -> Self {
Self::new(self.input.slice(range), self.namespace)
}
}
impl InputTakeAtPosition for ParsingContext<'_> {
type Item = char;
fn split_at_position<P, E: ParseError<Self>>(&self, predicate: P) -> IResult<Self, Self, E>
where
P: Fn(Self::Item) -> bool,
{
self.input
.position(predicate)
.map(|idx| Self::take_split(self, idx))
.ok_or(Err::Incomplete(Needed::Size(NonZero::new(1).unwrap())))
}
fn split_at_position1<P, E: ParseError<Self>>(
&self,
predicate: P,
e: ErrorKind,
) -> IResult<Self, Self, E>
where
P: Fn(Self::Item) -> bool,
{
match self.input.position(predicate) {
Some(0) => Err(Err::Error(E::from_error_kind(*self, e))),
Some(idx) => Ok(Self::take_split(self, idx)),
None => Err(Err::Incomplete(Needed::Size(NonZero::new(1).unwrap()))),
}
}
fn split_at_position_complete<P, E: ParseError<Self>>(
&self,
predicate: P,
) -> IResult<Self, Self, E>
where
P: Fn(Self::Item) -> bool,
{
match self.split_at_position(predicate) {
Err(Err::Incomplete(_)) => Ok(Self::take_split(self, self.input.input_len())),
elt => elt,
}
}
fn split_at_position1_complete<P, E: ParseError<Self>>(
&self,
predicate: P,
e: ErrorKind,
) -> IResult<Self, Self, E>
where
P: Fn(Self::Item) -> bool,
{
match self.input.position(predicate) {
Some(0) => Err(Err::Error(E::from_error_kind(*self, e))),
Some(idx) => Ok(Self::take_split(self, idx)),
None => Ok(Self::take_split(self, self.input.input_len())),
}
}
}
impl Offset for ParsingContext<'_> {
fn offset(&self, second: &Self) -> usize {
self.input.offset(second.input)
}
}
impl<'a, R> ParseTo<R> for ParsingContext<'a>
where
&'a str: ParseTo<R>,
{
fn parse_to(&self) -> Option<R> {
self.input.parse_to()
}
}