poe_data_tools 1.0.0

A library for working with Path of Exile game data
Documentation
use anyhow::anyhow;
use winnow::{
    Parser,
    ascii::{dec_uint, space1},
    combinator::{opt, repeat, repeat_till, separated_pair},
    token::{literal, rest},
};

use super::types::*;
use crate::file_parsers::{
    VersionedResult, VersionedResultExt,
    shared::{
        lift::{SliceParser, lift},
        winnow::{unquoted_str, version_line},
    },
};

fn emitter<'a>() -> impl SliceParser<'a, &'a str, Emitter> {
    winnow::trace!(
        "emitter",
        (
            lift(literal("{")), //
            repeat_till::<_, _, Vec<_>, _, _, _, _>(
                .., //
                lift(separated_pair(unquoted_str, space1, rest.map(String::from))),
                lift(literal("}")),
            ),
        )
            .map(|(_, (key_values, _))| Emitter::from_iter(key_values))
    )
}

pub fn parse_trl_str(contents: &str) -> VersionedResult<TRLFile> {
    let lines = contents
        .lines()
        .map(|l| l.trim())
        .filter(|l| !l.is_empty())
        .collect::<Vec<_>>();
    let mut lines = lines.as_slice();

    let num_emitters: usize = lift(dec_uint)
        .parse_next(&mut lines)
        .map_err(|e| anyhow!("Failed to parse file: {e:?}"))?;

    let version = opt(lift(version_line()))
        .parse_next(&mut lines)
        .map_err(|e| anyhow!("Failed to parse file: {e:?}"))?;

    let mut parser = (
        repeat(num_emitters, emitter()),
        rest.try_map(|lines: &[&str]| {
            if lines.is_empty() {
                Ok(None)
            } else {
                serde_json::from_str(&lines.concat()).map(Some)
            }
        }),
    )
        .map(|(emitters, payload)| TRLFile {
            version,
            emitters,
            payload,
        });

    let pet_file = parser
        .parse(lines)
        .map_err(|e| anyhow!("Failed to parse file: {e:?}"))
        .with_version(version)?;

    Ok(pet_file).with_version(version)
}