Merge Layered TOML Configs

Recursively merge TOML tables so environment overlays change only the keys they declare while preserving sibling settings.

RustConfig Management

Code

snippet
use toml::Value;

fn merge(base: &mut Value, overlay: &Value) {
    match (base, overlay) {
        (Value::Table(base_map), Value::Table(overlay_map)) => {
            for (key, value) in overlay_map {
                match base_map.get_mut(key) {
                    Some(existing) => merge(existing, value),
                    None => {
                        base_map.insert(key.clone(), value.clone());
                    }
                }
            }
        }
        (base_slot, _) => {
            *base_slot = overlay.clone();
        }
    }
}

fn main() -> Result<(), toml::de::Error> {
    let base: Value = r#"
[server]
port = 8080
host = "127.0.0.1"

[server.tls]
enabled = false
"#
    .parse()?;

    let overlay: Value = r#"
[server]
port = 9090

[server.tls]
enabled = true
"#
    .parse()?;

    let mut merged = base;
    merge(&mut merged, &overlay);
    let rendered = toml::to_string(&merged).expect("serialize merged config");
    println!("{rendered}");
    Ok(())
}