beancount-parser 2.6.0

A beancount file parser library for rust
Documentation
use std::collections::HashSet;

use nom::{combinator::ParserIterator, Finish};

use crate::{DirectiveContent, Entry, Error, RawEntry, Span, Tag};

type InnerIter<'i, F> = ParserIterator<Span<'i>, nom::error::Error<Span<'i>>, F>;

pub(crate) struct Iter<'i, F> {
    source: &'i str,
    inner: Option<InnerIter<'i, F>>,
    tag_stack: HashSet<Tag>,
}

impl<'i, F> Iter<'i, F> {
    pub(crate) fn new(source: &'i str, value: InnerIter<'i, F>) -> Self {
        Self {
            source,
            inner: Some(value),
            tag_stack: HashSet::new(),
        }
    }
}

impl<'i, D, F> Iterator for Iter<'i, F>
where
    for<'a> &'a mut InnerIter<'i, F>: Iterator<Item = RawEntry<D>>,
{
    type Item = Result<Entry<D>, Error>;
    fn next(&mut self) -> Option<Self::Item> {
        let inner = self.inner.as_mut()?;
        for entry in inner {
            match entry {
                RawEntry::Directive(mut d) => {
                    if let DirectiveContent::Transaction(trx) = &mut d.content {
                        trx.tags.extend(self.tag_stack.iter().cloned());
                    }
                    return Some(Ok(Entry::Directive(d)));
                }
                RawEntry::Option(o) => {
                    return Some(Ok(Entry::Option(o)));
                }
                RawEntry::Include(path) => {
                    return Some(Ok(Entry::Include(path)));
                }
                RawEntry::PushTag(tag) => {
                    self.tag_stack.insert(tag);
                }
                RawEntry::PopTag(tag) => {
                    self.tag_stack.remove(&tag);
                }
                RawEntry::Comment => (),
            }
        }
        match self.inner.take().unwrap().finish().finish() {
            Ok((rest, ())) if rest.fragment().is_empty() => None,
            Ok((input, ())) | Err(nom::error::Error { input, .. }) => {
                Some(Err(Error::new(self.source, input)))
            }
        }
    }
}