congen 0.1.0

congen helps you build configuration systems that support partial updates from structured changes and CLI input
Documentation
#![doc = include_str!("../README.md")]

#[cfg(feature = "clap")]
pub mod clap;
pub mod env;
pub mod internal;
mod lists;
mod option;
mod primitives;

/// Derive [`Configuration`] for a named struct.
///
/// This macro generates:
/// - an implementation of [`Configuration`] for the struct,
/// - a `<TypeName>Change` struct used as the associated `CongenChange`, and
///
/// # Basic usage:
///
/// ```rust
/// use congen::Configuration;
///
/// #[derive(Configuration, Debug)]
/// struct AppConfig {
///     retries: u32,
///     #[congen(default)]
///     api_token: Option<String>,
/// }
/// ```
///
/// # Attributes
///
/// The `#[congen(...)]` attribute can be used together with `#[derive(Configuration)]` on
/// the struct itself and on individual fields.
///
/// Struct-level attribute options:
/// - `#[congen(default)]`: Treat every field as if `#[congen(default)]` was set unless that
///   field already defines its own default behavior.
/// - `#[congen(debug)]`: Derive `Debug` for the generated `<TypeName>Change` type.
///
/// Field-level attribute options:
/// - `#[congen(default)]`: Use `<FieldType as congen::Configuration>::default()` when
///   `use-default` is requested for that field.
/// - `#[congen(rust_default)]`: Use `<FieldType as std::default::Default>::default()` when
///   `use-default` is requested for that field.
/// - `#[congen(default = <expr>)]`: Use the provided expression as the field default.
/// - `#[congen(inner_default = <expr>)]`: Override the default value used to initialize the
///   inner value when applying nested updates through container types like `Option<T>`.
///
/// # Default values
///
/// see the [crate documentation](crate)
pub use congen_derive::Configuration;

#[cfg(feature = "clap")]
pub use congen_derive::ValueEnumConfiguration;

#[cfg(feature = "clap")]
pub use clap::CongenClap;

pub use env::load_from_env;

use crate::internal::CongenInternal;

/// A data structure that allows applying partial changes.
///
/// Using [CongenClap] or [load_from_env] to apply a partial change to a [Configuration].
///
/// ```rust
/// use congen::{Configuration, load_from_env};
///
/// #[derive(Configuration, Debug)]
/// struct Config {
///     retries: u32,
///     #[congen(default)]
///     token: Option<String>,
/// }
///
/// let mut config = read_config_from_file("config.toml");
/// let change = load_from_env::<Config>("CONGEN").unwrap();
/// run_program(config.with_change(change));
///
/// # fn run_program(config: Config) {}
/// # fn read_config_from_file(_path: &str) -> Config {
/// #     Config {
/// #         retries: 3,
/// #         token: Some("abc".to_string()),
/// #     }
/// # }
/// ```
pub trait Configuration: CongenInternal {
    /// apply change to `self`
    fn apply_change(&mut self, change: Self::CongenChange) {
        <Self as CongenInternal>::apply_change_with_inner_default(self, change, None);
    }

    /// create a new [Configuration] with the `change` applied
    fn with_change(mut self, change: Self::CongenChange) -> Self {
        self.apply_change(change);
        self
    }
}