use std::collections::BTreeSet;
use figment::value::Dict;
use figment::{Figment, Metadata};
use crate::layer::DEFAULTS_NAME;
use crate::source::LoadSpec;
pub(super) fn apply_aliases(figment: Figment, spec: &LoadSpec<'_>) -> Figment {
let Some(aliases) = spec.aliases else {
return figment;
};
let mut figment = figment;
let pairs = aliases.pairs();
let mut filled: BTreeSet<&str> = BTreeSet::new();
let mut progressed = true;
while progressed {
progressed = false;
for (from, to) in &pairs {
if filled.contains(to.as_str()) {
continue;
}
let selected = figment.clone().select(super::section_profile(spec.key));
let supplied_above_defaults = selected
.find_metadata(to)
.is_some_and(|metadata| metadata.name != DEFAULTS_NAME);
if supplied_above_defaults {
continue;
}
let (section, from_path) = crate::aliases::split_section(from);
let source = match section {
Some(section) => figment.clone().select(super::section_profile(section)),
None => selected,
};
let Ok(value) = source.find_value(from_path) else {
continue;
};
let mut values = Dict::new();
crate::layer::insert_path(&mut values, to, value);
figment = figment.merge(Aliased {
values,
profile: figment::Profile::from(super::section_profile(spec.key)),
from: from.clone(),
supplier: source.find_metadata(from_path).cloned(),
});
filled.insert(to.as_str());
progressed = true;
}
}
figment
}
struct Aliased {
values: Dict,
profile: figment::Profile,
from: String,
supplier: Option<Metadata>,
}
impl figment::Provider for Aliased {
fn metadata(&self) -> Metadata {
self.supplier
.clone()
.unwrap_or_else(|| Metadata::named(format!("{ALIAS_PREFIX}{}", self.from)))
}
fn data(&self) -> figment::Result<figment::value::Map<figment::Profile, Dict>> {
let mut map = figment::value::Map::new();
map.insert(self.profile.clone(), self.values.clone());
Ok(map)
}
}
const ALIAS_PREFIX: &str = "an alias for ";