Treat multiple nested config objects (e.g. JSON or YAML files) as a single config object with precedence.
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.
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());
}
```
Currently right now it only supports serde_json
. My plan is to add
serde_yaml
and maybe some other formats as this project grows.
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.