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, float, space1},
    combinator::{alt, cond, opt, preceded as P, repeat},
};

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

pub fn item<'a>(version: u32) -> impl WinnowParser<&'a str, Item> {
    winnow::trace!(
        "item",
        (
            dec_uint,
            P(space1, quoted_str),
            cond(
                version >= 4,
                P(space1, quoted('"').and_then(filename("ao"))),
            ),
            P(space1, float),
            cond(
                version >= 3, //
                P(space1, float),
            ),
            P(space1, dec_uint),
            P(space1, dec_uint),
        )
            .map(
                |(uint1, stub, ao_file, float1, float2, uint2, uint3)| Item {
                    uint1,
                    stub,
                    ao_file,
                    float1,
                    float2,
                    uint2,
                    uint3,
                },
            )
    )
}

pub fn group<'a>(version: u32) -> impl SliceParser<'a, &'a str, Group> {
    winnow::trace!(
        "group",
        (
            lift((
                alt((quoted_str, unquoted_str)), //
                opt(P(space1, float)),
            )),
            repeat(0.., lift(item(version))),
        )
            .map(|((name, float), items)| Group { name, float, items })
    )
}

pub fn parse_clt_str(contents: &str) -> VersionedResult<CLTFile> {
    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 = (
        lift(float), //
        repeat(1.., group(version)),
    )
        .map(|(float1, groups)| CLTFile {
            version,
            float1,
            groups,
        });

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