use anyhow::Context as _;
use super::{Parser, Result};
use crate::{Die, DwarfDb};
pub struct And<P1, P2, T, U> {
pub(super) first: P1,
pub(super) second: P2,
pub(super) _marker: std::marker::PhantomData<(T, U)>,
}
impl<'db, T, U, P1, P2> Parser<'db, (T, U)> for And<P1, P2, T, U>
where
P1: Parser<'db, T>,
P2: Parser<'db, U>,
{
fn parse(&self, db: &'db dyn DwarfDb, entry: Die<'db>) -> Result<(T, U)> {
let first_result = self.first.parse(db, entry)?;
let second_result = self.second.parse(db, entry)?;
Ok((first_result, second_result))
}
}
pub struct Map<P, F, T> {
pub(super) parser: P,
pub(super) f: F,
pub(super) _marker: std::marker::PhantomData<T>,
}
impl<'db, T, U, P, F> Parser<'db, U> for Map<P, F, T>
where
P: Parser<'db, T>,
F: Fn(T) -> U,
{
fn parse(&self, db: &'db dyn DwarfDb, entry: Die<'db>) -> Result<U> {
let result = self.parser.parse(db, entry)?;
Ok((self.f)(result))
}
}
pub struct MapWithDb<P, F, T> {
pub(super) parser: P,
pub(super) f: F,
pub(super) _marker: std::marker::PhantomData<T>,
}
impl<'db, T, U, P, F> Parser<'db, U> for MapWithDb<P, F, T>
where
P: Parser<'db, T>,
F: Fn(&'db dyn DwarfDb, T) -> U,
{
fn parse(&self, db: &'db dyn DwarfDb, entry: Die<'db>) -> Result<U> {
let result = self.parser.parse(db, entry)?;
Ok((self.f)(db, result))
}
}
pub struct MapWithDbAndEntry<P, F, T> {
pub(super) parser: P,
pub(super) f: F,
pub(super) _marker: std::marker::PhantomData<T>,
}
impl<'db, T, U, P, F> Parser<'db, U> for MapWithDbAndEntry<P, F, T>
where
P: Parser<'db, T>,
F: Fn(&'db dyn DwarfDb, Die<'db>, T) -> U,
{
fn parse(&self, db: &'db dyn DwarfDb, entry: Die<'db>) -> Result<U> {
let result = self.parser.parse(db, entry)?;
Ok((self.f)(db, entry, result))
}
}
pub struct MapRes<P, F, T> {
pub(super) parser: P,
pub(super) f: F,
pub(super) _marker: std::marker::PhantomData<T>,
}
impl<'db, T, U, P, F> Parser<'db, U> for MapRes<P, F, T>
where
P: Parser<'db, T>,
F: Fn(T) -> Result<U>,
{
fn parse(&self, db: &'db dyn DwarfDb, entry: Die<'db>) -> Result<U> {
let result = self.parser.parse(db, entry)?;
(self.f)(result)
}
}
pub struct Then<P1, P2, T> {
pub(super) first: P1,
pub(super) second: P2,
pub(super) _marker: std::marker::PhantomData<T>,
}
impl<'db, U, P1, P2> Parser<'db, U> for Then<P1, P2, Die<'db>>
where
P1: Parser<'db, Die<'db>>,
P2: Parser<'db, U>,
{
fn parse(&self, db: &'db dyn DwarfDb, entry: Die<'db>) -> Result<U> {
let intermediate = self.first.parse(db, entry)?;
self.second.parse(db, intermediate)
}
}
impl<'db, U, P1, P2> Parser<'db, Option<U>> for Then<P1, P2, Option<Die<'db>>>
where
P1: Parser<'db, Option<Die<'db>>>,
P2: Parser<'db, U>,
{
fn parse(&self, db: &'db dyn DwarfDb, entry: Die<'db>) -> Result<Option<U>> {
self.first
.parse(db, entry)?
.map(|intermediate| self.second.parse(db, intermediate))
.transpose()
}
}
impl<'db, U, P1, P2> Parser<'db, U> for Then<P1, P2, Result<Die<'db>>>
where
P1: Parser<'db, Result<Die<'db>>>,
P2: Parser<'db, U>,
{
fn parse(&self, db: &'db dyn DwarfDb, entry: Die<'db>) -> Result<U> {
self.first
.parse(db, entry)?
.and_then(|intermediate| self.second.parse(db, intermediate))
}
}
pub struct Filter<P> {
pub(super) parser: P,
}
impl<'db, T, P> Parser<'db, Option<T>> for Filter<P>
where
P: Parser<'db, T>,
{
fn parse(&self, db: &'db dyn DwarfDb, entry: Die<'db>) -> Result<Option<T>> {
Ok(self.parser.parse(db, entry).ok())
}
}
pub struct Context<P> {
pub(super) parser: P,
pub(super) context: String,
}
impl<'db, T, P> Parser<'db, T> for Context<P>
where
P: Parser<'db, T>,
{
fn parse(&self, db: &'db dyn DwarfDb, entry: Die<'db>) -> Result<T> {
self.parser
.parse(db, entry)
.with_context(|| entry.format_with_location(db, &self.context))
}
}
pub fn all<T>(parsers: T) -> All<T> {
All { parsers }
}
pub struct All<T> {
pub(super) parsers: T,
}
macro_rules! impl_parse_all_for_tuples {
(
$($P:ident, $T:ident, $idx:tt),*
) => {
impl<'db, $($T, $P,)*> Parser<'db, ($($T,)*)> for All<($($P,)*)>
where
$($P: Parser<'db, $T>),*
{
fn parse(&self, _db: &'db dyn DwarfDb, _entry: Die<'db>) -> anyhow::Result<($($T,)*)> {
Ok((
$(
self.parsers.$idx.parse(_db, _entry)?,
)*
))
}
}
};
}
impl_parse_all_for_tuples!();
impl_parse_all_for_tuples!(P0, T0, 0);
impl_parse_all_for_tuples!(P0, T0, 0, P1, T1, 1);
impl_parse_all_for_tuples!(P0, T0, 0, P1, T1, 1, P2, T2, 2);
impl_parse_all_for_tuples!(P0, T0, 0, P1, T1, 1, P2, T2, 2, P3, T3, 3);
impl_parse_all_for_tuples!(P0, T0, 0, P1, T1, 1, P2, T2, 2, P3, T3, 3, P4, T4, 4);
impl_parse_all_for_tuples!(P0, T0, 0, P1, T1, 1, P2, T2, 2, P3, T3, 3, P4, T4, 4, P5, T5, 5);
impl_parse_all_for_tuples!(
P0, T0, 0, P1, T1, 1, P2, T2, 2, P3, T3, 3, P4, T4, 4, P5, T5, 5, P6, T6, 6
);
impl_parse_all_for_tuples!(
P0, T0, 0, P1, T1, 1, P2, T2, 2, P3, T3, 3, P4, T4, 4, P5, T5, 5, P6, T6, 6, P7, T7, 7
);