forgeconf 0.1.0

Declarative configuration loader for Rust structs powered by attribute macros.
Documentation
forgeconf-0.1.0 has been yanked.

Forgeconf

Forgeconf is a small attribute macro and runtime for loading configuration files into strongly typed Rust structs. It is built for services that need predictable merge semantics, compile-time validation, and the ability to override values from the command line or the environment without sprinkling glue code throughout the application.

Highlights

  • ๐Ÿงฑ Single source of truth โ€“ annotate your struct once and Forgeconf generates the loader, builder, and conversion logic.
  • ๐Ÿงช Compile-time safety โ€“ missing values or type mismatches become compile errors inside the generated code, so you fail fast during development.
  • ๐Ÿ”Œ Composable sources โ€“ merge any combination of files, CLI flags, and environment variables with explicit priorities.
  • ๐Ÿงฉ Nested structures โ€“ nested structs can be annotated with #[forgeconf] as well, enabling deeply nested configuration trees without boilerplate.
  • ๐Ÿงท Format agnostic โ€“ enable just the parsers you need through Cargo features (toml, yaml, json).

Install

Add Forgeconf to your workspace:

[dependencies]
forgeconf = "0.1"

The crate enables TOML and YAML parsing by default. Add json if you want JSON support, or disable defaults to pick a subset:

[dependencies.forgeconf]
version = "0.1"
default-features = false
features = ["json"]

Quick start

use forgeconf::{forgeconf, ConfigError};

#[forgeconf(config(path = "config/app.toml"))]
struct AppConfig {
    #[field(default = 8080)]
    port: u16,
    #[field(env = "APP_DATABASE_URL")]
    database_url: String,
}

fn main() -> Result<(), ConfigError> {
    let cfg = AppConfig::loader()
        .with_config() // load every `config(...)` entry
        .with_cli(200) // merge `--key=value` CLI arguments
        .load()?;

    println!("listening on {}", cfg.port);
    println!("db url: {}", cfg.database_url);
    Ok(())
}

Attribute reference

#[forgeconf(...)] accepts zero or more config(...) entries. Each entry takes:

key type description
path string (req.) Relative or absolute path to the file
format "toml" / ... Overrides format detection
priority u8 Higher numbers win when merging (default 10)

Field modifiers

Use #[field(...)] on struct fields to fine tune the behaviour:

option type effect
name string Rename the lookup key
insensitive bool Perform case-insensitive lookups
env string Pull from an environment variable first
cli string Check --<cli>=value CLI flags before files
default expression Fall back to the provided literal/expression
optional bool Treat Option<T> fields as optional

All lookups resolve in the following order:

  1. Field-level CLI override (#[field(cli = "...")])
  2. Field-level env override (#[field(env = "...")])
  3. Sources registered on the loader (with_cli, with_config, or add_source)

Loader API

The generated <Struct>Loader exposes:

  • with_config() โ€“ loads every config(...) entry from the attribute.
  • with_cli(priority) โ€“ merges parsed CLI arguments at the provided priority.
  • add_source(source) โ€“ supply any custom ConfigSource.
  • load() โ€“ merges the queued sources and deserializes the struct.

You can construct sources manually using items re-exported from the crate:

let cfg = AppConfig::loader()
    .add_source(forgeconf::ConfigFile::new("settings.toml"))
    .add_source(forgeconf::CliArguments::new().with_args(["--port=9090"]))
    .load()?;

Format support

Feature Dependency File extensions
toml toml crate .toml
yaml yaml-rust2 .yml, .yaml
json jzon .json

Each parser lives behind a feature flag. Disable defaults if you want to ship with no parsers enabled.

License

Forgeconf is released under the MIT License.