rclap is a Rust utility that helps you create command-line interfaces with the clap crate by reducing boilerplate code. It generates clap structures from a simple TOML configuration file, allowing you to define your application's command-line arguments, environment variables, and default values in one place.
1- Create a TOML File: Define your configuration settings in a simple TOML file, specifying the argument name, type, default value, and associated environment variable.
# Basic configuration
ip = { default = "localhost", env = "IP" }
port = { type = "int", default = "8080", env = "PORT" }
# Inline enum
style = { enum = "Style", variants = ["Light", "Dark", "System"], default = "Light", env = "STYLE" }
# Array type
colors = { type = "[char]", default = ['R','G','B'], env = "COLORS" }
# Optional values
debug = { type = "bool", optional = true, default = "false", env = "DEBUG" }
# Nested configuration
[database]
url = { default = "localhost:5432", env = "DB_URL" }
pool_size = { type = "int", default = "10", env = "DB_POOL_SIZE" }2- Apply the Macro: Use the #[config] macro on an empty struct in your Rust code. The macro reads the TOML file and generates the complete clap::Parser implementation for you.
#[config]
struct MyConfig;3- Parse and Use: Your application can then simply call MyConfig::parse() to handle all command-line and environment variable parsing.
fn main() {
let config = MyConfig::parse();
println!("Config: {:#?}", config);
println!("{}", &config.port);
}Define enums inline or reference external ones:
style = { enum = "Style", variants = ["Light", "Dark", "System"], default = "Light", env = "STYLE" }enum Style {
Light,
Dark,
System,
}For external enums:
log_level = { enum = "crate::LogLevel", default = "INFO", env = "LOG_LEVEL" }Use bracket notation for arrays:
colors = { type = "[char]", default = ['R','G','B'], env = "COLORS" }
digits = { type = "[int]", default = [1,2,3], env = "DIGITS" }Mark fields as optional with optional = true:
debug = { type = "bool", optional = true, default = "false", env = "DEBUG" }
cache = { type = "string", optional = true, env = "CACHE_DIR" }Create inner configuration structures using section headers. The [section] creates a struct:
app = { type = "AppConfig" }
[database]
url = { default = "localhost:5432", env = "DB_URL" }
pool_size = { type = "int", default = "10", env = "DB_POOL_SIZE" }The [database] section generates a Database struct.
Example from config_with_inner.toml
Convert all configuration to a HashMap for iteration:
let config = MyConfig::parse();
let map = config.s.iter_map();
for (key, value) in &map {
println!("{} = {}", key, value);
}Useful for:
- Dynamic config inspection
- Logging all active settings
- Serializing configuration to different formats
See main.rs for a working example.
rclap generates clear help messages showing available options, their environment variable names, and default values:
Usage: example [OPTIONS]
Options:
--"ip" <ip> connection URL [env: IP=] [default: localhost]
--"port" <port> Server port number [env: PORT=] [default: 8080]
-h, --help Print help
The equivalent for the above code will be generated by the macro:
#[derive(Debug, Clone, PartialEq, Parser)]
pub struct MyConfig {
///Server port number
#[arg(
id = "port",
default_value_t = 8080,
env = "PORT",
long = "port"
)]
pub port: i64,
///connection URL
#[arg(
id = "ip",
default_value = "localhost",
env = "URL",
long = "ip"
)]
pub ip: String,
}| Setting | Description |
|---|---|
| type | Data type: int, float, bool, string, path, [T] for arrays (e.g., [int], [char]) |
| env | Environment variable name for runtime override |
| default | Default value if neither env nor command line argument is set |
| doc | Documentation string displayed in help messages |
| enum | For inline enums: defines enum name and is used with variants |
| variants | Array of variant names for inline enum definitions |
| optional | Marks field as optional; value may be absent from config |
| long | Long flag name (same as clap); if not specified, the id value is used |
| short | Short flag character (same as clap) |
Enable the secret feature to access secure wrapper types for passwords, tokens, and API keys. When a field is marked with secret = true, its value is hidden in Display and Debug output.
Secret<S> - Generic wrapper for any type implementing CloneableSecret:
use rclap::Secret;
let password: Secret<String> = Secret::new("my_secret_password".to_string());
println!("{}", password); // outputs: *StringSecret - Specialized wrapper for strings:
use rclap::StringSecret;
let token = StringSecret::new("my_api_token");
println!("{}", token); // outputs: *Mark fields as secrets using the secret = true attribute:
pwd = { default = "changeme", secret = true }
pwd_r = { default = "changeme", optional = true, secret = true }
pwd_int = { default = "123", secret = true, type = "Int" }To access the actual value, use the expose_secret() method:
let config = MyConfig.parse();
println!("{}", config.pwd); // outputs: *
println!("{}", config.pwd.expose_secret()); // outputs: changemeExample from config_with_secret.toml
- config.toml
- multi_types.toml
- option.toml
- second_config.toml
- config_with_inner.toml
- config_with_secret.toml
The rclap utility is a macro generator that relies on two core dependencies:
clap: A powerful command-line argument parser for Rust. rclap uses it to parse command-line arguments and generate help messages.
toml: A library for parsing and handling TOML files. rclap uses it to read the configuration settings you define in your .toml file.
To use rclap, add the following to your Cargo.toml:
clap = { version = "4.5", features = ["env", "derive"] }Optional features:
[dependencies]
rclap = { version = "1.0", features = ["secrecy"] } # Enable secret wrapper types
[dev-dependencies]
clap = { version = "4.5", features = ["env", "derive"] }
serde = { version = "1.0", features = ["derive"] } # Required for serializationThe example folder contains more working samples.