Config and CLI
Validate configuration loaded with config-rs or figment against a vld schema, with every invalid key reported at startup.

vld-config takes the merged configuration from config-rs or figment (TOML, JSON, YAML, env, defaults), turns it into a serde_json::Value and parses it with your vld schema. You get a typed settings struct or a VldError listing every bad key.

Install

Cargo.toml
[dependencies]
vld = "0.5"
vld-config = "0.5"   # config-rs backend
config = "0.15"

figment instead (or as well):

Cargo.toml
[dependencies]
vld-config = { version = "0.5", default-features = false, features = ["figment"] }
figment = { version = "0.10", features = ["toml", "env"] }

Features

FeatureDefaultDescription
config-rsyesfrom_config, from_builder for config >=0.14, <0.16
figmentnofrom_figment for figment 0.10

Both can be enabled. The backend crates are not re-exported; add config / figment yourself in a matching version.

MSRV: 1.85 (see MSRV).

Example

use vld_config::prelude::*;

vld::schema! {
    #[derive(Debug)]
    pub struct AppSettings {
        pub host: String => vld::string().min(1),
        pub port: i64    => vld::number().int().min(1).max(65535),
        pub debug: bool  => vld::boolean().with_default(false),
    }
}

let config = config::Config::builder()
    .add_source(config::File::with_name("config").required(false))
    // Env values are strings: `try_parsing(true)` turns APP_PORT=8080 into a number.
    .add_source(config::Environment::with_prefix("APP").try_parsing(true))
    .build()
    .unwrap();

match from_config::<AppSettings>(&config) {
    Ok(s) => println!("listening on {}:{}", s.host, s.port),
    Err(e) => {
        eprintln!("{e}");
        std::process::exit(1);
    }
}

figment:

let figment = figment::Figment::new()
    .merge(figment::providers::Serialized::defaults(
        serde_json::json!({"host": "0.0.0.0", "port": 3000}),
    ))
    .merge(figment::providers::Env::prefixed("APP_"));

let settings: AppSettings = vld_config::from_figment(&figment).unwrap();

API

ItemDescription
from_config::<T>(&config::Config)Deserialize to JSON, then parse_coerced into T
from_builder::<T>(ConfigBuilder)Build the config, then as above
from_figment::<T>(&figment::Figment)Extract to JSON, then as above
from_value::<T>(&Value)Strict parse of a JSON value (no coercion)
from_value_coerced::<T>(&Value)The same coercion the backends use
VldConfigErrorSource(String) (loading failed) or Validation(VldError); implements Error with source()
preludefrom_* (except from_value_coerced), VldConfigError, vld::prelude::*

T is any VldParse type: vld::schema!, #[derive(Validate)], or vld-schemars' impl_vld_parse!.

Gotchas

  • Coercion: from_config, from_builder and from_figment use vld::schema::parse_coerced. A number or boolean the backend parsed is turned back into text where the schema wants a string (APP_HOST=12345 → "12345"), and a single value is wrapped where the schema wants an array. The text is the backend's parsed value, so a lossy parse ("01234" → 1234) gives "1234". from_value does none of this.
  • config-rs reads env values as strings unless try_parsing(true) is set; without it vld::number() fields fail on env overrides.
  • Errors carry the JSON path of the bad key (database.port); print them with {e} or the formatting helpers.