tf-demo-parser 0.6.4

parser for tf2 demo files
Documentation
use std::collections::HashMap;
use std::env;
use std::fs;

use main_error::MainError;
use tf_demo_parser::demo::packet::stringtable::StringTableEntry;
use tf_demo_parser::demo::parser::MessageHandler;
use tf_demo_parser::MessageType;
pub use tf_demo_parser::{Demo, DemoParser, Parse, ParserState};

#[cfg(feature = "jemallocator")]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

fn main() -> Result<(), MainError> {
    #[cfg(feature = "better-panic")]
    better_panic::install();

    #[cfg(feature = "trace")]
    tracing_subscriber::fmt::init();

    let args: Vec<_> = env::args().collect();
    if args.len() < 2 {
        println!("1 argument required");
        return Ok(());
    }
    let path = args[1].clone();
    let file = fs::read(path)?;
    let demo = Demo::new(&file);
    let parser = DemoParser::new_with_analyser(demo.get_stream(), StringTableHandler::default());
    let (_, tables) = parser.parse()?;
    if let Some(name) = args.get(2) {
        if name == "--tables" {
            for (name, _) in tables {
                println!("{name}");
            }
        } else {
            let table = tables.get(name).expect("table not found");
            for item in table {
                println!("{item}");
            }
        }
    } else {
        for (name, table) in tables {
            println!("{name}:");
            for item in table {
                println!("\t{item}");
            }
        }
    }
    Ok(())
}

#[derive(Default)]
struct StringTableHandler {
    pub tables: HashMap<String, Vec<String>>,
}

impl MessageHandler for StringTableHandler {
    type Output = HashMap<String, Vec<String>>;

    fn does_handle(message_type: MessageType) -> bool {
        matches!(
            message_type,
            MessageType::CreateStringTable | MessageType::UpdateStringTable
        )
    }

    fn handle_string_entry(
        &mut self,
        table: &str,
        index: usize,
        entries: &StringTableEntry,
        _parser_state: &ParserState,
    ) {
        let table = self.tables.entry(table.into()).or_default();
        if index < table.len() {
            table[index] = entries.text().into();
        } else {
            table.insert(index, entries.text().into());
        }
    }

    fn into_output(self, _state: &ParserState) -> Self::Output {
        self.tables
    }
}