Crate spicex

Crate spicex 

Source
Expand description

§SPICE

A complete configuration solution for Rust applications, inspired by Spice.

Spice is designed to work within an application and can handle all types of configuration needs and formats. It supports:

  • Setting defaults
  • Reading from JSON, TOML, YAML, INI configuration files
  • Reading from environment variables
  • Reading from command line flags
  • Reading from remote config systems (etcd, Consul)
  • Watching and re-reading of config files (live reload)

§Architecture Overview

Spice uses a layered configuration approach where different sources have different precedence levels. The precedence order (highest to lowest) is:

  1. Explicit calls - Values set directly via set() method
  2. Command line flags - Values from CLI arguments
  3. Environment variables - Values from environment
  4. Configuration files - Values from config files
  5. Key-value stores - Values from remote stores
  6. Default values - Fallback values

§Quick Start

use spicex::{Spice, ConfigValue};
use std::collections::HashMap;

// Create a new Spice instance
let mut viper = Spice::new();

// Set some default values
viper.set_default("database.host", ConfigValue::from("localhost")).unwrap();
viper.set_default("database.port", ConfigValue::from(5432i64)).unwrap();

// Load configuration from a file
viper.set_config_name("config");
viper.add_config_path("./configs");
// viper.read_in_config().unwrap(); // Uncomment when config file exists

// Set environment variable prefix
viper.set_env_prefix("MYAPP");
viper.set_automatic_env(true);

// Access configuration values
let host = viper.get_string("database.host").unwrap();
let port = viper.get_i64("database.port").unwrap();

println!("Database: {}:{}", host.unwrap_or_default(), port.unwrap_or_default());

§Configuration File Formats

Spice supports multiple configuration file formats:

§JSON

{
  "database": {
    "host": "localhost",
    "port": 5432
  },
  "debug": true
}

§YAML

database:
  host: localhost
  port: 5432
debug: true

§TOML

debug = true

[database]
host = "localhost"
port = 5432

§INI

debug = true

[database]
host = localhost
port = 5432

§Environment Variables

Environment variables are automatically mapped to configuration keys:

export MYAPP_DATABASE_HOST=localhost
export MYAPP_DATABASE_PORT=5432
export MYAPP_DEBUG=true

These will be available as database.host, database.port, and debug respectively.

§Command Line Flags

When using the cli feature, command line flags can be integrated:

use spicex::{Spice, FlagConfigLayer};
use clap::{Arg, Command};

let app = Command::new("myapp")
    .arg(Arg::new("host")
        .long("host")
        .value_name("HOST")
        .help("Database host"));

let args = vec!["myapp", "--host", "localhost"];
let matches = app.try_get_matches_from(args).unwrap();

let mut viper = Spice::new();
viper.bind_flags(matches);

§File Watching

Spice can watch configuration files for changes and automatically reload:

use spicex::Spice;

let mut viper = Spice::new();
viper.set_config_file("./config.json").unwrap();
viper.watch_config().unwrap();

// Register a callback for configuration changes
viper.on_config_change(|| {
    println!("Configuration changed!");
}).unwrap();

§Struct Deserialization

Configuration can be deserialized into Rust structs using serde:

use serde::Deserialize;
use spicex::{Spice, ConfigValue};

#[derive(Deserialize, Debug)]
struct DatabaseConfig {
    host: String,
    port: u16,
    ssl: bool,
}

#[derive(Deserialize, Debug)]
struct AppConfig {
    database: DatabaseConfig,
    debug: bool,
}

let mut viper = Spice::new();
viper.set_default("database.host", ConfigValue::from("localhost")).unwrap();
viper.set_default("database.port", ConfigValue::from(5432i64)).unwrap();
viper.set_default("database.ssl", ConfigValue::from(false)).unwrap();
viper.set_default("debug", ConfigValue::from(true)).unwrap();

let config: AppConfig = viper.unmarshal().unwrap();
println!("Config: {:?}", config);

§Error Handling

All operations return ConfigResult<T> which is an alias for Result<T, ConfigError>. The ConfigError enum provides detailed error information:

use spicex::{Spice, ConfigError};

let mut viper = Spice::new();
match viper.get_string("nonexistent.key") {
    Ok(Some(value)) => println!("Value: {}", value),
    Ok(None) => println!("Key not found"),
    Err(ConfigError::KeyNotFound { key }) => println!("Key '{}' not found", key),
    Err(e) => println!("Error: {}", e),
}

Re-exports§

pub use config::Spice;
pub use default_layer::DefaultConfigLayer;
pub use env_layer::EnvConfigLayer;
pub use error::ConfigError;
pub use error::ConfigResult;
pub use file_layer::FileConfigLayer;
pub use layer::ConfigLayer;
pub use layer::LayerPriority;
pub use value::ConfigValue;

Modules§

config
Core Spice configuration management struct and implementation.
default_layer
Default configuration layer implementation.
env_layer
Environment variable configuration layer implementation.
error
Error types and utilities for Spice configuration management.
file_layer
File-based configuration layer implementation.
layer
Configuration layer abstractions and priority management.
parser
Configuration format parsers for different file types.
value
Configuration value types and conversion utilities. Configuration value types and conversion utilities.
watcher
File system watching utilities for configuration files.

Constants§

VERSION