Structs & enums
The Config trait can be derived for structs and enums.
#![allow(unused)]
fn main() {
#[derive(Config)]
struct AppConfig {
pub base: String,
pub port: usize,
pub secure: bool,
pub allowed_hosts: Vec<String>,
}
#[derive(Config)]
enum Host {
Local,
#[setting(nested)]
Remote(HostConfig),
}
}
Enum caveats
Config can only be derived for enums with tuple or unit variants, but not struct/named
variants. Why not struct variants? Because with this pattern, the enum acts like a union type. This
also allows for Config functionality, like partials, merging, and validation, to be
applied to the contents of each variant.
If you’d like to support unit-only enums, you can use the
ConfigEnumtrait instead.
Attribute fields
The following fields are supported for the #[config] container attribute:
allow_unknown_fields- Removes the serdedeny_unknown_fieldsfrom the partial struct. Defaults tofalse.context- Sets the struct to be used as the context. Defaults toNone.env_prefix- Sets the prefix to use for environment variable mapping. Defaults toNone.partial- Forwards attributes to the partial.
#![allow(unused)]
fn main() {
#[derive(Config)]
#[config(allow_unknown_fields, env_prefix = "EXAMPLE_")]
struct ExampleConfig {
// ...
}
}
And the following for serde compatibility:
renamerename_all- Has no default. Field names are used exactly as written unless this is set.rename_all_fields(enum only) - Applies a casing to the fields of every variant.
Serde support
By default the Config macro will apply the following #[serde] to the
partial struct. The default and deny_unknown_fields ensure proper parsing and
layer merging.
#![allow(unused)]
fn main() {
#[serde(default, deny_unknown_fields)]
}
However, the deny_unknown_fields field can be customized, and we also support the rename and
rename_all fields, all via the top-level #[config] attribute.
#![allow(unused)]
fn main() {
#[derive(Config)]
#[config(allow_unknown_fields, rename = "ExampleConfig", rename_all = "snake_case")]
struct Example {
// ...
}
}
These values can also be applied using
#[serde], which is useful if you want to apply them to the main struct as well, and not just the partial struct.
Enum tagging
Serde’s tagging attributes are read straight off the #[serde] attribute and forwarded to the
partial, so untagged, tag, content, and expecting work as they normally would.
#![allow(unused)]
fn main() {
#[derive(Config)]
#[serde(untagged)]
enum Host {
Local,
#[setting(nested)]
Remote(HostConfig),
}
}
The derive registers serde as a helper attribute, so this is accepted even when the type derives
only Config and not Serialize or Deserialize.
A unit-only enum is always externally tagged, no matter what you set. Marking one
untaggedwould leave its variants deserializable only fromnull.