Derive Macro confique::Config

source · []
#[derive(Config)]
{
    // Attributes available to this derive:
    #[config]
}
Expand description

Derives (automatically implements) Config for a struct.

This only works for structs with named fields, but not for tuple structs, unit structs, enums, or unions.

Quick example

use confique::Config;
use std::net::IpAddr;

#[derive(Config)]
struct Conf {
    color: Option<String>,

    #[config(nested)]
    http: HttpConf,
}

#[derive(Config)]
struct HttpConf {
    #[config(env = "APP_PORT")]
    port: u16,

    #[config(default = "127.0.0.1")]
    bind: IpAddr,
}

This derives Config for the two structs.

  • HttpConf::port can be loaded from the environment variable APP_PORT.
  • HttpConf::bind has a default value of 127.0.0.1 (the string is turned into the IpAddr via its Deserialize impl). Thus a value for this field does not need to be present when loading configuration.
  • Conf::color is optional and does not need to be present when loading the configuration.

How to use

There are two types of fields distinguished by this macro: nested and leaf fields.

  • Nested fields: they have to be annotated with #[config(nested)] and contain a nested configuration object. The type of this field must implement Config. As implied by the previous statement, Option<_> as type for nested fields is not allowed.

  • Leaf fields: all fields not annotated with #[config (nested)], these contain your actual values. The type of such a field has to implement serde::Deserialize.

Doc comments on the struct and the individual fields are interpreted and stored in Meta. They are used in the formatting functions (e.g. toml::format).

Attributes

This macro currently recognizes the following attributes for leaf fields:

  • #[config(default = ...)]: sets a default value for this field. This is returned by Partial::default_values and, in most circumstances, used as a last “layer” to pull values from that have not been set in a layer of higher-priority. Currently, Boolean, float, integer and string values are allowed.

  • #[config(env = "KEY")]: assigns an environment variable to this field. In Partial::from_env, the variable is checked and deserialized into the field if present.

Special types for leaf fields

These types give a different meaning/semantic to the field. Please note that due to the limitations of derive macros, the type is checked literally. So it won’t work if you rename symbols or used full paths.

  • Option<T>: this marks the field as an optional field. All other fields are non-optional and will raise an error if while loading the configuration, no value has been set for them. Optional fields cannot have a #[config(default = ...)] attribute as that would not make sense.

What the macro generates

This macro emits one impl confique::Config for … { … } block. But in order to implement that trait, a partial type of your struct is also generated. That partial type lives in its own module and derives serde::Deserialize.

The example in the “Quick example” section above would expand to something like this:

impl confique::Config for Conf {
    type Partial = confique_partial_conf::PartialConf;
    ...
}
mod confique_partial_conf {
    #[derive(serde::Deserialize)]
    pub(super) struct PartialConf {
        pub(super) color: Option<String>,

        #[serde(default = "confique::Partial::empty")]
        pub(super) http: <HttpConf as confique::Config>::Partial,
    }

    impl confique::Partial for PartialConf { ... }
}

impl confique::Config for HttpConf {
    type Partial = confique_partial_http_conf::PartialHttpConf;
    ...
}
mod confique_partial_http_conf {
    #[derive(serde::Deserialize)]
    pub(super) struct PartialHttpConf {
        pub(super) port: Option<u16>,
        pub(super) bind: Option<IpAddr>,
    }

    impl confique::Partial for PartialHttpConf { ... }
}