use log::trace;
use crate::prelude::{Cursor, ParsingError, Matchable};
pub trait Parser<'c, C, T> {
type Error;
fn parse(&mut self, s: C) -> Result<(C, T), Self::Error>;
}
pub type StrFunc<T, E> = for<'c> fn(&'c str) -> Result<(&'c str, T), E>;
pub type StrMethod<T, X> = for<'c> fn(x: &'c X, &'c str) -> Result<(&'c str, T), ParsingError>;
impl<'c, T> Parser<'c, Cursor<'c>, T> for StrFunc<T, ParsingError> {
type Error = ParsingError;
fn parse(&mut self, c: Cursor<'c>) -> Result<(Cursor<'c>, T), ParsingError> {
trace!("#### fn(&'b str): {s}", s = c.cur.unwrap_or("-"));
let (s, t) = (self)(c.str()?)?;
Ok((Cursor::from(s), t))
}
}
impl<'c, C, T, F> Parser<'c, C, T> for F
where
F: FnMut(C) -> Result<(C, T), ParsingError>,
{
type Error = ParsingError;
fn parse(&mut self, s: C) -> Result<(C, T), ParsingError> {
(self)(s)
}
}
impl<'c, T, X> Parser<'c, Cursor<'c>, T> for (&'c X, StrMethod<T, X>) {
type Error = ParsingError;
fn parse(&mut self, c: Cursor<'c>) -> Result<(Cursor<'c>, T), ParsingError> {
trace!("#### fn(context, &str): {s}", s = c.cur.unwrap_or("-"));
let (s, t) = (self.1)(self.0, c.str()?)?;
Ok((Cursor::from(s), t))
}
}
#[cfg(test)]
mod tests {
use crate::{
parser::{Parser, StrFunc, StrMethod},
prelude::{Cursor, ParsingError},
};
#[test]
fn test_casting() {
fn lp<'a, T>(s: Cursor<'a>, mut p: impl Parser<'a, Cursor<'a>, T, Error = ParsingError>) {
let _ = p.parse(s);
}
#[derive(Default)]
struct StructEx;
impl StructEx {
fn parse_ex2<'a>(&self, s: &'a str) -> Result<(&'a str, String), ParsingError> {
Ok((s, String::from("Example2")))
}
fn parse_ex4<'a>(&self, s: Cursor<'a>) -> Result<(Cursor<'a>, String), ParsingError> {
Ok((s, String::from("Example4")))
}
}
fn parse_ex1(s: &str) -> Result<(&str, String), ParsingError> {
Ok((s, String::from("Example1")))
}
fn parse_ex3(s: Cursor) -> Result<(Cursor, String), ParsingError> {
Ok((s, String::from("Example3")))
}
let selfie = StructEx;
let f: for<'a> fn(&'a str) -> Result<(&'a str, String), ParsingError> = parse_ex1;
let tup_ex2 = (&selfie, StructEx::parse_ex2 as StrMethod<_, _>);
lp("parse_ex1 as ... ".into(), f);
lp("parse_ex1 as StrFunc ".into(), parse_ex1 as StrFunc<_, _>);
lp("(&selfie,f) ".into(), tup_ex2);
lp("parse_ex3 ".into(), parse_ex3);
lp("|c| self.parse_ex4(c)".into(), |c| selfie.parse_ex4(c));
lp("|c| parse_ex(c) ".into(), |c| parse_ex3(c));
}
}