Expand description
Type-safe configuration with layered overrides.
gifnoc provides a config! macro that generates a configuration struct
with typed fields and compile-time defaults. The struct implements the
Configurable trait, whose update method
applies overrides from any source — environment variables, CLI flags, TOML
or YAML files — without clobbering unrelated fields.
§Quick start
use gifnoc::{config, Configurable};
config! {
ServerConfig {
host: String = "localhost",
port: u32 = 8080u32,
}
}
let config = ServerConfig::default();
assert_eq!(config.host, "localhost");
assert_eq!(config.port, 8080);§Sources
All source functions return serde_json::Value and plug into
Configurable::update via the same flatten → merge → nest pipeline.
Sources are layered by chaining .update() calls — later calls win:
let (actions, flags) = gifnoc::args::parse();
let config = AppConfig::default()
.update(gifnoc::env::with_prefix("APP")) // env vars override defaults
.update(flags); // CLI flags override env vars| Source | Function | Convention |
|---|---|---|
| Environment variables | env::with_prefix | APP_KEY, APP_SECTION__KEY |
| CLI flags | args::parse | --key value, --section.key value |
| JSON file | json::from_file | round-trips Configurable::to_json output |
| TOML file | [toml::from_file] | (requires feature toml) |
| YAML file | [yaml::from_file] | (requires feature yaml) |
§Recommended pattern: composition root
Build the full config once in main, then distribute slices to subsystems
via their constructors. Each subsystem receives only the section it needs,
keeping dependencies narrow:
use gifnoc::{config, Configurable};
config! { ServerConfig { port: u32 = 8080u32 } }
config! { AppConfig { server: ServerConfig = ServerConfig::default() } }
struct Server { port: u32 }
impl Server {
fn new(config: &ServerConfig) -> Self {
Server { port: config.port }
}
fn run(&self) { println!("listening on :{}", self.port); }
}
fn main() {
let (actions, flags) = gifnoc::args::parse();
let config = AppConfig::default()
.update(gifnoc::env::with_prefix("APP"))
.update(flags);
let server = Server::new(&config.server);
for action in &actions {
match action.as_str() {
"serve" => server.run(),
other => { eprintln!("unknown action: {other}"); std::process::exit(1); }
}
}
}Modules§
Macros§
- config
- Defines a configuration struct with typed fields and compile-time defaults.
Traits§
- Configurable
- Trait for configuration structs that support layered overrides.