tier 0.1.17

Rust configuration library for layered TOML, env, and CLI settings
Documentation
use std::collections::BTreeMap;

use crate::EnvDecoder;
use crate::path::path_matches_pattern;

use super::super::CustomEnvDecoder;

pub(super) fn custom_env_decoder_for_path<'a>(
    path: &str,
    custom_env_decoders: &'a BTreeMap<String, CustomEnvDecoder>,
) -> Option<&'a CustomEnvDecoder> {
    let mut best = None::<((usize, usize, Vec<bool>), &CustomEnvDecoder)>;

    for (pattern, decoder) in custom_env_decoders {
        if !path_matches_pattern(path, pattern) {
            continue;
        }

        let score = decoder_match_score(pattern);
        match &mut best {
            Some((best_score, best_decoder)) if score > *best_score => {
                *best_score = score;
                *best_decoder = decoder;
            }
            None => best = Some((score, decoder)),
            _ => {}
        }
    }

    best.map(|(_, decoder)| decoder)
}

pub(super) fn env_decoder_for_path(
    path: &str,
    env_decoders: &BTreeMap<String, EnvDecoder>,
) -> Option<EnvDecoder> {
    let mut best = None::<((usize, usize, Vec<bool>), EnvDecoder)>;

    for (pattern, decoder) in env_decoders {
        if !path_matches_pattern(path, pattern) {
            continue;
        }

        let score = decoder_match_score(pattern);
        match &mut best {
            Some((best_score, best_decoder)) if score > *best_score => {
                *best_score = score;
                *best_decoder = *decoder;
            }
            None => best = Some((score, *decoder)),
            _ => {}
        }
    }

    best.map(|(_, decoder)| decoder)
}

fn decoder_match_score(pattern: &str) -> (usize, usize, Vec<bool>) {
    let segments = pattern.split('.').collect::<Vec<_>>();
    (
        segments.len(),
        segments.iter().filter(|segment| **segment != "*").count(),
        segments.iter().map(|segment| *segment != "*").collect(),
    )
}