Crate smart_config
source ·Expand description
smart-config – schema-driven layered configuration system with support of multiple configuration formats.
§Overview
The task solved by the library is merging configuration input from a variety of prioritized sources
(JSON and YAML files, env variables, command-line args etc.) and converting this input to strongly typed
representation (i.e., config structs or enums). As with other config systems, config input follows the JSON object model
(see Value), with each value enriched with its origin (e.g., a path in a specific JSON file,
or a specific env var). This allows attributing errors during deserialization.
The defining feature of smart-config is its schema-driven design. Each config type has associated metadata
defined with the help of the DescribeConfig derive macro; deserialization is handled by the accompanying DeserializeConfig macro.
Metadata includes a variety of info extracted from the config type:
- Parameter info: name (including aliases and renaming), help (extracted from doc comments), type, deserializer for the param etc.
- Nested configurations.
Multiple configurations are collected into a global ConfigSchema. Each configuration is mounted at a specific path.
E.g., if a large app has an HTTP server component, it may be mounted at api.http. Multiple config types may be mounted
at the same path (e.g., flattened configs); conversely, a single config type may be mounted at multiple places.
As a result, there doesn’t need to be a god object uniting all configs in the app; they may be dynamically collected and deserialized
inside relevant components.
This information provides rich human-readable info about configs. It also assists when preprocessing and merging config inputs. For example, env vars are a flat string -> string map; with the help of a schema, it’s possible to:
- Correctly nest vars (e.g., transform the API_HTTP_PORTvar into aportvar insidehttpobject insideapiobject)
- Transform value types from strings to expected types.
Preprocessing and merging config sources is encapsulated in ConfigRepository.
§TL;DR
- Rich, self-documenting configuration schema.
- Utilizes the schema to enrich configuration sources and intelligently merge them.
- Doesn’t require a god object uniting all configs in the app; they may be dynamically collected and deserialized inside relevant components.
- Supports lazy parsing for complex / multi-component apps (only the used configs are parsed; other configs are not required).
- Supports multiple configuration formats and programmable source priorities (e.g., base.yml+ overrides from theoverrides/dir in the alphabetic order + env vars).
- Rich and complete deserialization errors including locations and value origins.
- Built-in support for secret params.
§Crate features
§primitive-types
(Off by default)
Implements deserialization for basic Ethereum types like H256 (32-byte hash)
and U256 (256-bit unsigned integer).
§Examples
§Basic workflow
use smart_config::{
    config, ConfigSchema, ConfigRepository, DescribeConfig, DeserializeConfig, Yaml, Environment,
};
#[derive(Debug, DescribeConfig, DeserializeConfig)]
pub struct TestConfig {
    pub port: u16,
    #[config(default_t = "test".into())]
    pub name: String,
    #[config(default_t = true)]
    pub tracing: bool,
}
let schema = ConfigSchema::new(&TestConfig::DESCRIPTION, "test");
// Assume we use two config sources: a YAML file and env vars,
// the latter having higher priority.
let yaml = r"
test:
  port: 4000
  name: app
";
let yaml = Yaml::new("test.yml", serde_yaml::from_str(yaml)?)?;
let env = Environment::from_iter("APP_", [("APP_TEST_PORT", "8000")]);
// Add both sources to a repo.
let repo = ConfigRepository::new(&schema).with(yaml).with(env);
// Get the parser for the config.
let parser = repo.single::<TestConfig>()?;
let config = parser.parse()?;
assert_eq!(config.port, 8_000); // from the env var
assert_eq!(config.name, "app"); // from YAML
assert!(config.tracing); // from the default value§Declaring type as well-known
use std::collections::HashMap;
use smart_config::{
    de::{Serde, WellKnown, WellKnownOption}, metadata::BasicTypes,
    DescribeConfig, DeserializeConfig,
};
#[derive(Debug, serde::Serialize, serde::Deserialize)]
enum CustomEnum {
    First,
    Second,
}
impl WellKnown for CustomEnum {
    // signals that the type should be deserialized via `serde`
    // and the expected input is a string
    type Deserializer = Serde![str];
    const DE: Self::Deserializer = Serde![str];
}
// Signals that the type can be used with an `Option<_>`
impl WellKnownOption for CustomEnum {}
// Then, the type can be used in configs basically everywhere:
#[derive(Debug, DescribeConfig, DeserializeConfig)]
struct TestConfig {
    value: CustomEnum,
    optional: Option<CustomEnum>,
    repeated: Vec<CustomEnum>,
    map: HashMap<String, CustomEnum>,
}Re-exports§
- pub use self::de::DeserializeConfig;
- pub use self::error::ParseErrorCategory;
Modules§
- Configuration deserialization logic.
- FallbackValuesources.
- Configuration metadata.
- Testing tools for configurations.
- Parameter and config validation and filtering.
- Enriched JSON object model that allows to associate values with origins.
- Visitor pattern for configs.
Macros§
- Constructor ofSerdetypes / instances.
Structs§
- A wrapper providing a clear reminder that the wrapped value represents the number of bytes.
- Mutable reference to a specific configuration insideConfigSchema.
- Parser of configuration input in aConfigRepository.
- Reference to a specific configuration insideConfigSchema.
- Configuration repository containing zero or more configuration sources. Sources are preprocessed and merged according to the providedConfigSchema.
- Schema for configuration. Can contain multiple configs bound to different paths.
- Prioritized list of configuration sources. Can be used to push multiple sources at once into aConfigRepository.
- Marker error forDeserializeConfigoperations. The error info os stored inDeserializeContextasParseErrors.
- Configuration sourced from environment variables.
- Marker for key–value / flat configuration sources (e.g., env variables or command-line args).
- Marker for hierarchical configuration sources (e.g. JSON or YAML files).
- JSON-based configuration source.
- Config parameter deserialization errors.
- Collection ofParseErrors returned fromConfigParser::parse().
- Wraps a hierarchical source into a prefix.
- Configuration serialization options.
- Information about a source returned fromConfigRepository::sources().
- YAML-based configuration source.
Traits§
- Source of configuration parameters that can be added to aConfigRepository.
- Kind of aConfigSource.
- Describes a configuration (i.e., a group of related parameters).
- Provides an example for this configuration. The produced config can be used in tests etc.
Type Aliases§
- Error together with its origin.
Derive Macros§
- Derives theDescribeConfigtrait for a type.
- Derives theDeserializeConfigtrait for a type.
- Derives theExampleConfigtrait for a type.