forgeconf

Crates.ioforgeconf
lib.rsforgeconf
version0.2.0
created_at2025-11-29 16:56:35.513849+00
updated_at2025-11-30 03:32:17.479761+00
descriptionDeclarative configuration loader for Rust structs powered by attribute macros.
homepage
repositoryhttps://github.com/chikof/forgeconf
max_upload_size
id1957038
size27,968
Chiko (chikof)

documentation

README

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.

Table of Contents

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, YAML, and regex-powered validators 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", "regex"]

Disable regex if you want to skip the regex crate entirely, or re-enable it explicitly (as shown above) when using validators::matches_regex.

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
validate expression Invoke a validator after parsing (repeatable)

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)

Validators

Validators are plain expressions that evaluate to something callable with (&T, &str) and returning Result<(), ConfigError>. You can reference free functions, closures, or the helpers under forgeconf::validators:

fn ensure_https(value: &String, key: &str) -> Result<(), ConfigError> {
    if value.starts_with("https://") {
        Ok(())
    } else {
        Err(ConfigError::mismatch(key, "https url", value.clone()))
    }
}

#[forgeconf]
struct SecureConfig {
    #[field(validate = forgeconf::validators::range(1024, 65535))]
    port: u16,
    #[field(
        validate = ensure_https,
        validate = forgeconf::validators::len_range(12, 128),
        validate = forgeconf::validators::matches_regex(regex::Regex::new("^https://").unwrap()),
    )]
    endpoint: String,
}

The most common helpers:

  • non_empty(), min_len(n), max_len(n), and len_range(min, max) โ€“ work with any type implementing validators::HasLen (Strings, Vecs, maps, sets, โ€ฆ).
  • range(min, max) โ€“ enforce numeric/string bounds via PartialOrd.
  • one_of([..]) โ€“ restrict values to a predefined set.
  • matches_regex(regex::Regex) โ€“ ensure the value matches a regular expression (enable the regex Cargo feature and add the regex crate to your Cargo.toml when using this helper).

Each helper returns a closure that you can combine or wrap to build higher-level policies.

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.

Commit count: 0

cargo fmt