Mem_Parser 0.1.0

Zero-copy log parser with mmap input, streaming lines, and optional bump arena AST
Documentation
//! Optional bump arena parse tree sharing `&str` views into source text.

use bumpalo::Bump;

use crate::lexer::{fields_on_line, LineView, LogDialect};
use crate::span::Span;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct FieldNode<'src> {
    pub key: &'src str,
    pub value: &'src str,
}

/// AST for a single line; field slice memory is owned by the arena (`'arena`).
#[derive(Debug)]
pub struct LineAst<'src, 'arena> {
    pub line_span: Span,
    pub fields: &'arena [FieldNode<'src>],
}

/// Parses lines into bump-allocated ASTs. Combine with [`Bump::reset`] between lines for cheap
/// rollback of speculative work.
pub struct ArenaParser {
    dialect: LogDialect,
}

impl ArenaParser {
    pub fn new(dialect: LogDialect) -> Self {
        Self { dialect }
    }

    pub fn dialect(&self) -> LogDialect {
        self.dialect
    }

    pub fn parse_line_to_ast<'src, 'arena>(
        &self,
        bump: &'arena Bump,
        line: LineView<'src>,
    ) -> &'arena LineAst<'src, 'arena> {
        let temp = fields_on_line(line, self.dialect);
        let slot: &mut [FieldNode<'src>] =
            bump.alloc_slice_fill_copy(temp.len(), FieldNode { key: "", value: "" });
        for (dst, src) in slot.iter_mut().zip(&temp) {
            *dst = FieldNode {
                key: src.key,
                value: src.value,
            };
        }
        let fields: &'arena [FieldNode<'src>] = slot;
        bump.alloc(LineAst {
            line_span: line.span(),
            fields,
        })
    }
}