poe_data_tools 1.0.0

A library for working with Path of Exile game data
Documentation
use anyhow::anyhow;
use winnow::{
    Parser,
    ascii::space1,
    combinator::{alt, cond, opt, preceded, repeat},
};

use super::types::*;
use crate::file_parsers::{
    VersionedResult, VersionedResultExt,
    shared::{
        lift::{SliceParser, lift},
        winnow::{
            WinnowParser, filename, quoted, quoted_str, uint as U, unquoted_str, version_line,
        },
    },
};

fn file<'a>() -> impl WinnowParser<&'a str, GenFile> {
    winnow::trace!(
        "file",
        (
            U,
            preceded(
                space1,
                quoted('"').and_then(alt((
                    filename("arm"), //
                    filename("tdt"),
                ))),
            ),
            repeat(0.., preceded(space1, unquoted_str)),
        )
            .map(|(weight, path, rotations)| GenFile {
                weight,
                path,
                rotations,
            })
    )
}

fn section<'a>(version: u32) -> impl SliceParser<'a, &'a str, Section> {
    winnow::trace!(
        "section",
        (
            winnow::trace!("header", lift((quoted_str, opt(preceded(space1, U))))),
            winnow::trace!("file_count", cond(version == 1, lift(U))),
            winnow::trace!("files", repeat(0.., lift(file()))),
        )
            .map(|((name, uint1), _, files)| Section { name, files, uint1 })
    )
}

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

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

    let mut parser = (
        cond(version == 1, lift(U)), //
        repeat(0.., section(version)),
    )
        .map(|(_num_sections, sections)| GFTFile { version, sections });

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