config-lib 0.9.4

Enterprise-grade multi-format configuration library supporting 8 formats (CONF, INI, Properties, JSON, XML, HCL, TOML, NOML) with sub-50ns caching, hot reloading, and comprehensive validation.
Documentation

Features

Multi-Format Support

  • CONF - Built-in parser for standard .conf files (default)
  • INI - Full INI file parsing with sections, comments, and data type detection
  • JSON - JSON format with edit capabilities and serialization
  • XML - Zero-copy XML parsing with quick-xml for Java/.NET environments
  • HCL - HashiCorp Configuration Language for DevOps workflows
  • Properties - Complete Java .properties file parsing with Unicode and escaping
  • NOML - Advanced configuration with dynamic features (feature: noml)
  • TOML - TOML format with format preservation (feature: toml)

Enterprise Performance

  • Sub-50ns Cache Access Target - Multi-tier caching designed for sub-50ns reads on hot paths
  • Zero-Copy Parsing - Minimized allocations and string operations where possible
  • Lock-Free Read Paths - Poison-resistant locking with graceful failure recovery
  • Hot Value Cache - Ultra-fast access for frequently used values
  • Cache Hit Ratio Tracking - Built-in performance statistics and monitoring

Note on benchmark numbers: detailed criterion-backed benchmark numbers will land with v1.0.0. Until then, performance claims should be treated as targets, not guarantees.

Production Features

  • Configuration Hot Reloading - File watching with thread-safe Arc swapping
  • Audit Logging System - Structured event logging with multiple sinks and severity filtering
  • Environment Variable Overrides - Smart caching with prefix matching and type conversion
  • Schema Validation - Trait-based validation system with feature gates
  • Format Preservation - Maintains comments, whitespace, and original formatting
  • Async Native - Full async/await support throughout the API

Reliability & Safety

  • Zero Unsafe Code - All unwrap() calls eliminated, comprehensive error handling
  • Type Safety - Rich type system with automatic conversions and validation
  • Enterprise Error Handling - Production-ready error messages with context preservation
  • Comprehensive Testing - Extensive unit, integration, and doc test coverage

Why Choose config-lib?

Unified Multi-Format Support

Unlike single-format libraries, config-lib provides seamless access to 8 configuration formats through one consistent API. No need to learn different libraries for TOML, JSON, XML, and HCL - one API handles them all with automatic format detection.

Enterprise-Grade Performance

Multi-tier caching with lock-free read paths is designed to deliver sub-50ns cached access on hot paths. Built for high-throughput applications with minimal performance overhead.

Production-Ready Reliability

Zero unsafe code, comprehensive error handling, and poison-resistant locking ensure your configuration system won't crash your application. Extensive testing coverage validates edge cases and error conditions.

Developer Experience First

Rich type system with automatic conversions, format preservation for round-trip editing, and detailed error messages with source location context. No more cryptic parsing errors or manual type casting.

Advanced Enterprise Features

Hot reloading without service interruption, structured audit logging for compliance, environment variable overrides with smart caching, and schema validation with custom rules - features typically requiring multiple libraries.


Installation

Add to your Cargo.toml:

[dependencies]
config-lib = "0.9"

# For enhanced functionality, enable optional features:
config-lib = { version = "0.9", features = [
    "json",           # JSON format support with serialization
    "xml",            # XML format support with quick-xml backend  
    "hcl",            # HashiCorp Configuration Language support
    "toml",           # TOML format support with preservation
    "noml",           # NOML format support with dynamic features
    "validation",     # Schema validation and type checking
    "async",          # Async operations and hot reloading
    "env-override",   # Environment variable override system
    "audit",          # Audit logging and compliance features
] }

Feature Recommendations:

  • Minimal: Use default features for CONF/INI/Properties support
  • Web Applications: Add "json", "env-override", "validation"
  • DevOps Tools: Add "hcl", "toml", "async", "audit"
  • Enterprise Systems: Add "xml", "validation", "audit", "env-override"
  • Full Featured: Include all features for maximum flexibility

Quick Start

use config_lib::Config;

// Parse any supported format automatically
let mut config = Config::from_string(r#"
[database]
host = "localhost"
port = 5432
username = "admin"

[app]
name = "MyApp"
debug = true
"#, None)?;

// Access values with type safety
let host = config.get("database.host")?.as_string()?;
let port = config.get("database.port")?.as_integer()?;
let debug = config.get("app.debug")?.as_bool()?;

// Modify configuration (preserves format and comments)
config.set("database.port", 5433)?;
config.set("app.version", "1.0.0")?;

println!("Connecting to {}:{}", host, port);

Multi-Format Support

use config_lib::Config;

// All 8 formats now fully operational
let config = Config::from_string(r#"
[server]
port = 8080
host = "localhost"
"#, Some("toml"))?;

// Consistent API patterns across all parsers
let port = config.get("server.port")?.as_integer()?;
let timeout = config.get("server.timeout")
    .and_then(|v| v.as_integer().ok())
    .unwrap_or(30);
let name = config.get("app.name")
    .and_then(|v| v.as_string().ok())
    .unwrap_or_else(|| "DefaultApp".to_string());

// Check existence
if config.contains_key("server.ssl") {
    println!("SSL configuration found");
}

Read-only mode and forward-compatible options

ConfigOptions is the structured place to express the small set of behaviors that should not be enabled by default — making a Config read-only, sizing the cache (v0.9.5), etc. The struct is #[non_exhaustive] so v0.9.x can add new knobs without breaking SemVer; callers go through the consuming builder methods.

use config_lib::{Config, ConfigOptions};

// Default options — caching on, writes allowed.
let _cfg = Config::with_options(ConfigOptions::default());

// Read-only configuration for a hot path that must never be mutated.
let opts = ConfigOptions::new().read_only(true);
let mut locked = Config::with_options(opts);
assert!(locked.set("foo", "bar").is_err());   // rejected

Deprecated in v0.9.4. EnterpriseConfig and the multi-tier cache_stats() / make_read_only() API are deprecated as of v0.9.4. They continue to compile and work through the v0.9.x line and the v1.x deprecation window, but new code should use Config + ConfigOptions directly. The lock-free caching that made EnterpriseConfig distinct lands on the unified Config in v0.9.5. See .dev/ROADMAP.md for the full timeline and examples/enterprise_demo.rs for a side-by-side migration table.

Default Configuration Settings

config-lib provides multiple powerful methods for setting default/preset values that serve as fallbacks when keys are missing from configuration files. This ensures your application always has sensible defaults while allowing configuration files to override specific values.

Method 1: ConfigBuilder with Presets (Recommended)

use config_lib::{ConfigBuilder, Value};
use std::collections::HashMap;

// Set up comprehensive default values before loading config files
let mut defaults = HashMap::new();
defaults.insert("app.name".to_string(), Value::String("MyApplication".to_string()));
defaults.insert("app.version".to_string(), Value::String("1.0.0".to_string()));
defaults.insert("app.debug".to_string(), Value::Bool(false));

// Server defaults
defaults.insert("server.host".to_string(), Value::String("localhost".to_string()));
defaults.insert("server.port".to_string(), Value::Integer(8080));
defaults.insert("server.timeout".to_string(), Value::Integer(30));
defaults.insert("server.workers".to_string(), Value::Integer(4));

// Database defaults
defaults.insert("database.host".to_string(), Value::String("localhost".to_string()));
defaults.insert("database.port".to_string(), Value::Integer(5432));
defaults.insert("database.pool_size".to_string(), Value::Integer(10));
defaults.insert("database.timeout".to_string(), Value::Integer(60));

// Logging defaults
defaults.insert("logging.level".to_string(), Value::String("info".to_string()));
defaults.insert("logging.file".to_string(), Value::String("app.log".to_string()));
defaults.insert("logging.max_size".to_string(), Value::String("10MB".to_string()));

// Create config with defaults, then load from file
let config = ConfigBuilder::new()
    .with_defaults(defaults)         // Apply presets first
    .from_file("app.conf")?          // File values override presets
    .build()?;

// All values are guaranteed to exist (from file or defaults)
let app_name = config.get("app.name")?.as_string()?;           // File value or "MyApplication"
let port = config.get("server.port")?.as_integer()?;           // File value or 8080
let pool_size = config.get("database.pool_size")?.as_integer()?; // File value or 10
let log_level = config.get("logging.level")?.as_string()?;      // File value or "info"

Method 2: Inline defaults at the access site

The simplest pattern when defaults are only needed at the call site — no parallel defaults table to maintain, no unwrap on a key that may not exist.

use config_lib::Config;

let config = Config::from_file("production.conf")?;

let environment = config
    .get("app.environment")
    .and_then(|v| v.as_string().ok())
    .map(str::to_owned)
    .unwrap_or_else(|| "development".to_string());

let cache_ttl: i64 = config
    .get("cache.ttl")
    .and_then(|v| v.as_integer().ok())
    .unwrap_or(3600);

let workers: i64 = config
    .get("server.workers")
    .and_then(|v| v.as_integer().ok())
    .unwrap_or(4);

Migrated from EnterpriseConfig::set_default / get_or_default (deprecated v0.9.4). The richer separate-defaults-table API returns in v0.9.5 once ConfigOptions gains a defaults field alongside the caching layer. See examples/enterprise_demo.rs for the side-by-side migration table.

Method 3: Inline Defaults with get_or()

use config_lib::Config;

// Load configuration file
let config = Config::from_file("app.conf")?;

// Provide defaults inline when accessing values
let app_config = AppConfig {
    name: config.get_or("app.name", "DefaultApp".to_string()),
    port: config.get_or("server.port", 8080),
    debug: config.get_or("app.debug", false),
    timeout: config.get_or("server.timeout", 30),
    
    // Database configuration with sensible defaults
    db_host: config.get_or("database.host", "localhost".to_string()),
    db_port: config.get_or("database.port", 5432),
    db_pool_size: config.get_or("database.pool_size", 10),
    
    // Feature flags with conservative defaults
    analytics_enabled: config.get_or("features.analytics", false),
    cache_enabled: config.get_or("features.cache", true),
    monitoring_enabled: config.get_or("features.monitoring", false),
};

Best Practices for Default Configuration

  1. Use Sensible Defaults: Choose defaults that work for most use cases
  2. Document Defaults: Keep defaults in sync with documentation
  3. Environment-Specific: Use different defaults for dev/staging/production
  4. Type Safety: Ensure defaults match expected types
  5. Validation: Validate both defaults and overrides
  6. Performance: Use Enterprise config for high-performance scenarios
// Example: Production-ready defaults with validation
use config_lib::{ConfigBuilder, Value, validation::Validator};

// Production defaults (secure and performant)
let defaults = HashMap::from([
    ("server.host".to_string(), Value::String("127.0.0.1".to_string())), // Secure default
    ("server.port".to_string(), Value::Integer(8443)),                     // HTTPS default
    ("server.ssl_enabled".to_string(), Value::Bool(true)),                // Secure by default
    ("database.ssl_mode".to_string(), Value::String("require".to_string())), // Secure DB
    ("logging.level".to_string(), Value::String("warn".to_string())),      // Production logging
    ("features.debug".to_string(), Value::Bool(false)),                   // Disable debug
]);

// Validation rules for all values (including defaults)
let validator = Validator::new()
    .add_rule("server.port", ValidationRule::IntegerRange(1, 65535))
    .add_rule("server.host", ValidationRule::Required)
    .add_rule("logging.level", ValidationRule::OneOf(vec!["error", "warn", "info", "debug"]));

let config = ConfigBuilder::new()
    .with_defaults(defaults)
    .from_file("production.conf")?
    .with_validation(validator)         // Validate defaults + file values
    .build()?;

Environment Variable Integration

use config_lib::{Config, env_override::EnvOverride};

// Load configuration with environment variable overrides
let mut config = Config::from_file("app.conf")?;

// Enable environment variable overrides with prefix
let env_override = EnvOverride::new()
    .with_prefix("MYAPP_")  // Maps MYAPP_DATABASE_HOST to database.host
    .with_separator("_")    // Use underscore as path separator
    .case_insensitive();    // MYAPP_database_HOST also works

config.apply_env_overrides(&env_override)?;

// Now environment variables override file values:
// MYAPP_DATABASE_HOST=prod.db.com overrides database.host from file
// MYAPP_SERVER_PORT=9090 overrides server.port from file
let host = config.get("database.host")?.as_string()?;  // From env or file
let port = config.get("server.port")?.as_integer()?;   // From env or file

Configuration Validation & Type Safety

use config_lib::{Config, validation::{Validator, ValidationRule}};

// Define validation rules for configuration
let validator = Validator::new()
    .add_rule("server.port", ValidationRule::IntegerRange(1, 65535))
    .add_rule("database.host", ValidationRule::Required)
    .add_rule("app.name", ValidationRule::StringPattern(r"^[a-zA-Z][a-zA-Z0-9_-]*$"))
    .add_rule("logging.level", ValidationRule::OneOf(vec!["debug", "info", "warn", "error"]));

let mut config = Config::from_file("app.conf")?;

// Validate configuration before use
validator.validate(&config)?;  // Fails fast with detailed error messages

// Safe access with automatic type conversion
let port = config.get("server.port")?.as_integer()?;  // Guaranteed valid range
let log_level = config.get("logging.level")?.as_string()?;  // Guaranteed valid value

Hot Reloading & Audit Logging

use config_lib::{Config, audit};

// Enable audit logging
let audit_logger = audit::AuditLogger::new()
    .with_console_sink(audit::Severity::Info)
    .with_file_sink("config_audit.log", audit::Severity::Warning)?;

// Hot reloading configuration
let config = Config::from_file_with_hot_reload("app.conf", move |new_config| {
    println!("Configuration reloaded!");
    audit_logger.log_reload("app.conf", "admin");
})?;

Advanced Multi-File Configuration

use config_lib::{ConfigBuilder, ConfigMergeStrategy};

// Load and merge multiple configuration files
let config = ConfigBuilder::new()
    .from_file("default.conf")?     // Base configuration
    .merge_file("environment.json", ConfigMergeStrategy::Override)?  // Environment overrides
    .merge_file("local.toml", ConfigMergeStrategy::Additive)?        // Local additions
    .merge_file("secrets.hcl", ConfigMergeStrategy::SecureOverride)? // Secure values
    .build()?;

// Access merged configuration
let database_url = config.get("database.url")?.as_string()?;  // From secrets.hcl
let app_name = config.get("app.name")?.as_string()?;          // From default.conf
let debug_mode = config.get("debug")?.as_bool()?;             // From environment.json

Status: Late Beta — On the Path to v1.0.0

Current Version: 0.9.x — late beta, API stabilizing, structurally mature. Target: 1.0.0 stable, scheduled per the roadmap in .dev/ROADMAP.md.

What's complete:

  • Universal Format Support - All 8 configuration formats with consistent API (CONF, INI, JSON, XML, HCL, Properties, NOML, TOML)
  • Multi-Tier Caching - Designed for sub-50ns cached reads on hot paths
  • Production Safety - Zero unsafe code, comprehensive error handling, poison-resistant locking
  • Advanced Features - Hot reloading, audit logging, environment overrides, schema validation
  • Developer Experience - Rich type system, format preservation (NOML/TOML), automatic type conversion
  • Quality Assurance - Comprehensive test suite, zero clippy warnings

What's planned for v1.0.0:

  • Unified Config API (consolidation underway — EnterpriseConfig deprecated in v0.9.4, data-model merger lands with caching in v0.9.5)
  • Lock-free cached reads with verified sub-50ns benchmarks
  • Event-driven hot reload via notify (inotify / FSEvents / ReadDirectoryChangesW)
  • Fuzz-tested parsers for every format
  • Stability contract: API frozen for the lifetime of v1.x

Performance targets (to be verified by committed benchmarks before v1.0.0):

  • <50ns cached value access on hot paths
  • <500ns cached write
  • <100ms hot-reload detection latency (event-driven)
  • Zero-allocation hot-path reads

Note on API stability: The public API is not yet frozen. Expect refinements through 0.9.x releases. The v1.0.0 release will lock down the stability contract documented in docs/STABILITY-1.0.md.


Documentation & Resources

Documentation

External Resources

Getting Started Guides

Common Use Cases

  • Web Applications: Environment overrides, JSON/TOML configs
  • DevOps Tools: HCL integration, audit logging, hot reloading
  • Enterprise Systems: XML support, validation, caching
  • Microservices: Multi-format support, environment-based configuration

Troubleshooting


Version Compatibility

  • Rust: 1.82+ (currently); MSRV will be lowered to 1.75 in v1.0.0 per portfolio standard
  • Edition: 2021 (currently); will move to 2024 in v1.0.0
  • MSRV Policy: Once v1.0.0 ships, MSRV is guaranteed within the last 12 stable Rust releases
  • API Stability: Pre-1.0 — expect refinements. v1.0.0 will freeze the public API.
  • Feature Flags: All optional features maintain independent compatibility

Development Setup

git clone https://github.com/jamesgober/config-lib.git
cd config-lib
cargo test --all-features  # Run comprehensive test suite
cargo bench               # Performance benchmarks
cargo clippy              # Lint checks (should show zero warnings)

Contributing

We welcome contributions! See our Contributing Guide for details.