use crate::{types::ParserOutput, ParseContext, ParseIter, Parser, Reported, Result};
pub trait Mapping<T> {
type RawOutput: ParserOutput;
fn apply(&self, value: T) -> Self::RawOutput;
}
impl<F, T, U> Mapping<T> for F
where
T: ParserOutput,
F: Fn(T::UserType) -> U,
{
type RawOutput = (U,);
fn apply(&self, value: T) -> Self::RawOutput {
(self(value.into_user_type()),)
}
}
#[derive(Clone, Copy)]
pub struct MapParser<P, F> {
pub(crate) inner: P,
pub(crate) mapper: F,
}
pub struct MapParseIter<'parse, P, F>
where
P: Parser + 'parse,
{
inner: P::Iter<'parse>,
mapper: &'parse F,
}
impl<P, F> Parser for MapParser<P, F>
where
P: Parser,
F: Mapping<P::RawOutput>,
{
type Output = <F::RawOutput as ParserOutput>::UserType;
type RawOutput = F::RawOutput;
type Iter<'parse> = MapParseIter<'parse, P, F>
where
P: 'parse,
F: 'parse;
fn parse_iter<'parse>(
&'parse self,
context: &mut ParseContext<'parse>,
start: usize,
) -> Result<Self::Iter<'parse>, Reported> {
let iter = self.inner.parse_iter(context, start)?;
let mapper = &self.mapper;
Ok(MapParseIter {
inner: iter,
mapper,
})
}
}
impl<'parse, P, F> ParseIter<'parse> for MapParseIter<'parse, P, F>
where
P: Parser,
F: Mapping<P::RawOutput>,
{
type RawOutput = F::RawOutput;
fn match_end(&self) -> usize {
self.inner.match_end()
}
fn backtrack(&mut self, context: &mut ParseContext<'parse>) -> Result<(), Reported> {
self.inner.backtrack(context)
}
fn convert(&self) -> F::RawOutput {
let value = self.inner.convert();
self.mapper.apply(value)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Skip;
impl<T> Mapping<T> for Skip {
type RawOutput = ();
fn apply(&self, _value: T) {}
}
pub type SkipParser<P> = MapParser<P, Skip>;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct SingleValue;
impl<T: ParserOutput> Mapping<T> for SingleValue {
type RawOutput = (T::UserType,);
fn apply(&self, value: T) -> Self::RawOutput {
(value.into_user_type(),)
}
}
pub type SingleValueParser<P> = MapParser<P, SingleValue>;
#[doc(hidden)]
pub fn map<P, T, F>(parser: P, mapper: F) -> MapParser<P, F>
where
P: Parser,
F: Fn(P::Output) -> T,
{
MapParser {
inner: parser,
mapper,
}
}
#[allow(dead_code)]
pub fn skip<P>(parser: P) -> SkipParser<P>
where
P: Parser,
{
SkipParser {
inner: parser,
mapper: Skip,
}
}
pub fn single_value<P>(parser: P) -> SingleValueParser<P>
where
P: Parser,
{
SingleValueParser {
inner: parser,
mapper: SingleValue,
}
}