apollo-configuration 0.4.0

A typed, friendly configuration system for Apollo products.
Documentation
use apollo_configuration::ErrorCollector;
use apollo_configuration::configuration;
use std::collections::HashMap;

#[configuration]
struct HeaderOverride {
    name: String,
    value: String,
}

#[configuration]
struct Config {
    #[config(validate = unique_headers)]
    headers: Vec<HeaderOverride>,
}

fn unique_headers(headers: &[HeaderOverride], mut errors: ErrorCollector<'_>) {
    let mut seen_headers = HashMap::new();

    for (index, header) in headers.iter().enumerate() {
        if let Some(prev_index) = seen_headers.insert(&header.name, index) {
            let labels = vec![
                miette::LabeledSpan::at(
                    errors.nest(prev_index).span(),
                    "header first overridden here",
                ),
                miette::LabeledSpan::at(errors.nest(index).span(), "header overridden again here"),
            ];
            errors.report(miette::diagnostic!(
                code = "example::duplicate_header",
                labels = labels,
                "each header name can only be overridden once"
            ));
        }
    }
}

fn main() -> miette::Result<()> {
    let _config: Config = apollo_configuration::parse_yaml(
        r#"
        headers:
          - { name: example_name, value: example_value }
          - { name: other_name, value: xxx }
    "#,
        &Default::default(),
    )
    .expect("no duplicates: parses correctly");

    apollo_configuration::parse_yaml::<Config>(
        r#"
        headers:
          - { name: example_name, value: example_value }
          - { name: other_name, value: xxx }
          - { name: example_name, value: duplicate }
    "#,
        &Default::default(),
    )
    .map_err(miette::Report::new)?;

    Ok(())
}