Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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)] populates env_key. A key derived from an env_prefix depends on the prefix in effect at runtime, so it isn’t known here.