config-generator 0.1.3

A procedural macro for generating a configuration loader from an input struct.
Documentation
//! The [ConfigGenerator] derive macro is intended to simplify the process of writing
//! configuration loading boilerplate. It currently provides two main features:
//! TOML loading, and loading of values from environment variables.
//!
//! # Features
//!
//! By default, the `load_toml` feature is enabled, supplying a `with_toml` function implementation
//! on the input struct, and consequently requiring the [serde] and [toml] crates. This feature can
//! be disabled, and these crates removed, if the user so chooses.
//!
//! # Usage
//!
//! The macro is used by applying it to a struct via `#[derive(ConfigGenerator)`.
//!
//! ```
//! use config_generator::ConfigGenerator;
//!
//! #[derive(ConfigGenerator, Default)]
//! struct Config {
//!   #[env_key = "NAME_ENV_KEY"]
//!   pub name: String,
//!   #[env_key = "THREAD_COUNT"]
//!   pub thread_count: u32,
//!   #[env_key = "ALLOWED_ORIGINS"]
//!   pub allowed_origins: Vec<String>,
//!   #[env_key = "ASSETS_PATH"]
//!   pub assets_path: Option<String>,
//! }
//! ```
//!
//! This generates a private struct called `Optional[InputStruct]`. Thus, in the example above,
//! `OptionalConfig` would be generated. The generated optional struct is identical to the input
//! struct except that each of its fields is an [Option<T>]. This field is used internally to track
//! loaded data and apply it to the configuration struct when the user calls the `with_toml` or
//! `with_environment` functions to load values.
//!
//! Note that the user is expected to derive [Default] or implement some other means of obtaining
//! a starting point for configuration loading, such as a `new` function.
//!
//! For example, the following basic example loads values from an input toml file.
//! ```
//! use config_generator::ConfigGenerator;
//!
//! #[derive(ConfigGenerator, Default)]
//! struct Config {
//!   pub name: String,
//! }
//!
//! fn main() {
//!   let config = Config::default().with_toml(&"tests/tomls/simple_config.toml");
//! }
//! ```
//!
//! Similarly, the following example would load values from the environment, specifically
//! from the `NAME_KEY` environment variable annotated above the `name` field.
//! ```
//! use config_generator::ConfigGenerator;
//!
//! #[derive(ConfigGenerator, Default)]
//! struct Config {
//!   #[env_key = "NAME_KEY"]
//!   pub name: String,
//! }
//!
//! fn main() {
//!   let config = Config::default().with_env();
//! }
//! ```
//!
//! These functions can also be composed together. When composed, a latter-executed function
//! will superimpose loaded values on the prior config.
//! ```
//! use config_generator::ConfigGenerator;
//!
//! #[derive(ConfigGenerator, Default)]
//! struct Config {
//!   #[env_key = "NAME_KEY"]
//!   pub name: String,
//! }
//!
//! fn main() {
//!   let config = Config::default()
//!     .with_toml(&"tests/tomls/simple_config.toml")
//!     .with_env();
//! }
//! ```
//!
//! Superimposing values follows certain rules:
//! 1. If the original struct had an [Option<T>] field, the value for that field will _only_ be
//! replaced if the new value is [Some]. A subseqently-loaded [None] value will _not_ be applied.
//! 2. If the original struct had a [Vec<T>] field, subsequently-loaded values will be _combined_
//! with prior values, such that the [Vec] has each new value pushed to the end.
//! 3. For all other types, if a value is loaded, then that value will replace any previously-set value.

pub use config_gen_macro_impl::ConfigGenerator;