rust-stackedconfig

Treat multiple nested config objects (e.g. JSON or YAML files) as a single config object with precedence.

Why does this library exist?

This is a fun, small side-project for me to learn rust better, but my goal is for it to be good enough eventually for someone else to use seriously.

But why I want to use it?

Have you ever had the situation where your application had complex configuration? Something like this contrived example?

yaml notifications: email: address: user@example.com on_new_post: false on_new_message: true appearance: theme: dark font: family: Arial size: 14pt web: proxy: http: http://proxy.com https: https://proxy.com ssl_verify: true trusted_hosts: - crates.io - rust-lang.org credentials: username: null token: null

And you wanted to have multiple config files, such as on the system level in $APPDIR/app_config.yaml, on the user level at $HOME/app_config.yaml, and on the project level at $PROJECTDIR/app_config.yaml. Managing multiple config files with fallback is a pain. This library aims to make it easy to work with:

```rust extern crate serde_json; extern crate stackedconfig;

use serdejson::{Value, fromstr}; use stackedconfig::{ConfigStack};

fn main() { // Normally would load these from disk let systemconf: Value = fromstr(r#" { "notifications": { "email": { "onnewpost": true, "onnewmessage": true } }, "appearance":{ "theme": "light", "font": { "family": "Arial", "size": "14pt" } } "web": { "proxy": { "http": "http://proxy.com", "https": "https://proxy.com" }, "sslverify": true, "trustedhosts": [] }, "credentials": { "username": null, "token": null } } "#)?; let userconf: Value = fromstr(r#" { "notifications": { "email": { "address": "user@example.com" } }, "appearance": { "theme": "dark" }, "web": { "trustedhosts": ["crates.io", "rust-lang.org"] }, "credentials": { "username": "bheklilr", "token": "123456abcdef" } } "#)?; let stack = ConfigStack::new() .stack(systemconf) .stack(user_conf); // Nested access is available, separator can be customized to any character // with the with_sep method. println!("{}", stack.get("notifications/email/address")?.unwrap()); // Calls to get return a ConfigStack, so sub-sections could be passed to // the relevant parts of your application println!("{}", stack.get("appearance")?.get("theme")?.unwrap()); // The last config stacked takes precedence when doing lookups. // Values can be unwrapped from the stack for actual use later. println!("{}", stack.get("web/proxy/http")?.unwrap()); } ```

Limitations

Currently right now it only supports serde_json. My plan is to add serde_yaml and maybe some other formats as this project grows.

License

I put it under MIT, but honestly I really don't care what anyone does with this code. It is provided as-is. If you find a bug, feel free to submit an issue, or even better submit a PR fixing it.