Context
Context is an important mechanism that allows for different default values, merge strategies, and validation rules to be used, for the same configuration struct, depending on context!
To begin, a context is a struct with a default implementation.
#![allow(unused)]
fn main() {
#[derive(Default)]
struct ExampleContext {
pub some_value: bool,
pub another_value: usize,
}
}
Context must then be associated with a
Config derived struct through the
context attribute field.
#![allow(unused)]
fn main() {
#[derive(Config)]
#[config(context = ExampleContext)]
struct ExampleConfig {
// ...
}
}
And then passed to the
ConfigLoader::load_with_context()
method.
#![allow(unused)]
fn main() {
let context = ExampleContext {
some_value: true,
another_value: 10,
};
let result = ConfigLoader::<ExampleConfig>::new()
.url(url_to_config)?
.load_with_context(&context)?;
}
Refer to the default values, merge strategies, and validation rules sections for more information on how to use context.
Metadata
Alongside the configuration itself, the derive records a little metadata about each
setting, reachable with
Config::settings().
It returns a map keyed by the serde name of each setting, or by position for unnamed ones.
#![allow(unused)]
fn main() {
for (name, setting) in ExampleConfig::settings() {
println!("{name}: {}", setting.type_alias);
if let Some(key) = &setting.env_key {
println!(" reads {key}");
}
if let Some(nested) = &setting.nested {
println!(" has {} nested settings", nested.len());
}
}
}
Each entry carries the setting’s type_alias (the Rust type as written), its env_key, and a
nested map when the setting holds another nested config.
Only an explicit
#[setting(env)]populatesenv_key. A key derived from anenv_prefixdepends on the prefix in effect at runtime, so it isn’t known here.