use crate::Configuration; use std::collections::HashSet; mod parsing; fn check_configs_equal( cfg1: &Configuration, cfg2: &Configuration, ) -> Result<(), Box> { fn check_configs_equal_at( cfg1: &Configuration, cfg2: &Configuration, prefix: &str, ) -> Result<(), Box> { let (keys1, keys2): (HashSet<&str>, HashSet<&str>) = if let Some(k) = prefix.strip_suffix('.') { (cfg1.subkeys(k).collect(), cfg2.subkeys(k).collect()) } else { (cfg1.keys().collect(), cfg2.keys().collect()) }; for key in keys1.difference(&keys2) { return Err(format!( "Key {prefix}{key} appears at {}, but not in other configuration", cfg1.location(&format!("{prefix}{key}")).unwrap() ) .into()); } for key in keys2.difference(&keys1) { return Err(format!( "Key {prefix}{key} appears at {}, but not in other configuration", cfg2.location(&format!("{prefix}{key}")).unwrap() ) .into()); } for key in &keys1 { let full_key = format!("{prefix}{key}"); let val1 = cfg1.get(&full_key); let val2 = cfg2.get(&full_key); if val1 != val2 { return Err(format!( "Mismatch between values for key {full_key} defined as {val1:?} at {}, but defined as {val2:?} at {}", cfg1.location(&full_key) .map_or("".into(), |x| format!("{x}")), cfg2.location(&full_key) .map_or("".into(), |x| format!("{x}")), ) .into()); } check_configs_equal_at(cfg1, cfg2, &format!("{full_key}."))?; } Ok(()) } check_configs_equal_at(cfg1, cfg2, "") }