aethellib 0.8.2

Composable text generation primitives over target-specific TOML corpora with provenance tracking.
Documentation
use aethellib::engine::combinators::{
    chance, concat, lit, pick, recall, sequence, weighted_choice,
};
use aethellib::prelude::*;

fn main() {
    let corpus = Corpus::from_files(
        &["example/data/weapon_test_data.toml"],
        "weapon",
        None,
        None,
    )
    .expect("failed to load weapon corpus");

    let ctx = Engine::new(&corpus, rand::rng())
        // weapon name: "<prefix> <type> [<suffix>]" — suffix is added 85 % of the time
        .with_rule(concat(
            "weapon_name",
            concat(
                "prefix_type",
                pick("px", "name".to_string(), "prefix".to_string()),
                concat(
                    "space",
                    lit(" "),
                    pick("ty", "type".to_string(), "type".to_string()),
                ),
            ),
            chance(
                "optional_suffix",
                0.85,
                concat(
                    "space",
                    lit(" "),
                    pick("sx", "name".to_string(), "suffix".to_string()),
                ),
            ),
        ))
        // use recall to reuse the generated weapon name as part of the suffix,
        // creating names like "[weapon name] The Second"
        .with_rule(sequence(
            "weapon_name",
            vec![
                Box::new(recall("recalled_name", "weapon_name")),
                Box::new(lit("The Second")),
            ],
            Some(" "),
        ))
        // quality
        .with_rule(pick(
            "rarity",
            "qualities".to_string(),
            "rarity".to_string(),
        ))
        .with_rule(pick(
            "condition",
            "qualities".to_string(),
            "condition".to_string(),
        ))
        // visuals
        .with_rule(pick(
            "material",
            "visuals".to_string(),
            "materials".to_string(),
        ))
        .with_rule(pick("accent", "visuals".to_string(), "accents".to_string()))
        // weighted elemental trait: mundane is intentionally most common
        .with_rule(weighted_choice(
            "element",
            vec![
                (60, Box::new(lit("Mundane"))),
                (18, Box::new(lit("Flaming"))),
                (12, Box::new(lit("Frosted"))),
                (07, Box::new(lit("Storm-touched"))),
                (03, Box::new(lit("Voidbound"))),
            ],
        ))
        .generate()
        .expect("generation failed");

    let get = |key: &str| ctx.get_previous(key).unwrap().value.as_str();

    println!("─ Generated Weapon ─────────────────────────────────");
    println!("  Name       {} {}", get("element"), get("weapon_name"));
    println!("  Rarity     {} · {}", get("rarity"), get("condition"));
    println!("  Material   {}, {}", get("material"), get("accent"));
    println!("  Recall     {}", get("recalled_name"));
}