getargs-derive 0.1.0

Clap-style #[derive] command-line argument parser for no_std and embedded Rust: zero allocation, compile-time help, subcommands. Built on getargs.
Documentation

getargs-derive

crates.io docs.rs CI codecov License: MIT MSRV

A Clap-style #[derive] command-line argument parser for no_std and embedded Rust. Describe your CLI as a struct, and getargs-derive generates a zero-allocation parser on top of getargs, with compile-time help, subcommands, helpful errors and shell completions. If you know Clap's derive API, you already know this one.

Why getargs-derive?

  • no_std and no allocation by default. The parser only needs core: parsed values and errors borrow the arguments, and repeated values fit in fixed-capacity collections. It runs the same on a microcontroller, in a kernel or in a regular binary.
  • Help computed at compile time. --help, --version and the help of every subcommand are &'static str constants built by the macro, so no help-formatting code ends up in your binary.
  • Clap-familiar attributes. #[arg(short, long, default_value_t = ...)], doc comments as help text, #[derive(ValueEnum)], #[derive(Subcommand)], #[command(flatten)], env, conflicts_with, requires, argument groups, aliases, Count flags and more, with Clap's help layout and error wording.
  • Helpful errors. Clap-style messages with "did you mean" suggestions for misspelled options and subcommands, and compile-time diagnostics for invalid attributes instead of runtime panics.
  • Shell completions and man pages. With the std feature, generate bash, zsh and fish completion scripts and a roff man page from the same struct.
  • Small dependency tree. At run time, only getargs, which has no dependencies itself, plus heapless if you enable it.
  • Non-UTF-8 arguments. Parse raw &[u8] arguments anywhere, and OsString/PathBuf fields with std.

Installation

cargo add getargs-derive getargs

or in Cargo.toml:

[dependencies]
getargs-derive = "0.1"
getargs = "0.5"

No feature is enabled by default:

Feature Enables
(none) Everything not listed below, in no_std without an allocator. Repeated values are stored in Values<T, N>.
heapless heapless::Vec<T, N> fields for repeated values, stored inline without allocation.
alloc Vec<T> fields for repeated values.
std Environment variable fallbacks from the process environment, shell completions and man pages, OsStr/Path/PathBuf fields and from_args_os. Implies alloc.

For a regular command-line application, enable std:

cargo add getargs-derive --features std

Quick Start

use getargs_derive::{GetArgs, ValueEnum};

#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
enum Format {
    Json,
    Yaml,
    Toml,
}

/// Convert configuration files between formats.
#[derive(Debug, GetArgs)]
#[command(name = "confconv", version = "1.0.0")]
struct Cli<'a> {
    /// File to convert.
    input: &'a str,
    /// Output format.
    #[arg(short, long, value_enum, default_value_t = Format::Toml)]
    format: Format,
    /// Write the result to this file instead of standard output.
    #[arg(short, long)]
    output: Option<&'a str>,
    /// Print more details, repeat for even more.
    #[arg(short, long, action = Count)]
    verbose: u8,
}

fn main() {
    let args: Vec<String> = std::env::args().skip(1).collect();
    let cli = match Cli::from_args(args.iter().map(String::as_str)) {
        Ok(cli) => cli,
        Err(error) if error.is_help() || error.is_version() => {
            println!("{error}");
            std::process::exit(0);
        }
        Err(error) => {
            eprintln!("error: {error}");
            std::process::exit(2);
        }
    };
    println!("{cli:?}");
}

confconv --help prints the help generated at compile time, the Cli::HELP constant:

Convert configuration files between formats

Usage: confconv [OPTIONS] <INPUT>

Arguments:
  <INPUT>  File to convert

Options:
  -f, --format <FORMAT>  Output format [default: toml] [possible values: json, yaml, toml]
  -o, --output <OUTPUT>  Write the result to this file instead of standard output
  -v, --verbose...       Print more details, repeat for even more
  -h, --help             Print help
  -V, --version          Print version

and a typo gets a suggestion:

$ confconv config.json --frmat yaml
error: unexpected argument '--frmat' found

  tip: a similar argument exists: '--format'

The parser never prints or exits by itself: from_args takes any iterator of &str and returns the struct or an Error, so the same code works in tests, in no_std firmware reading arguments from a serial console, or behind parse when you already have a getargs::Options. With the std feature, Cli::from_args_os() reads std::env::args_os() directly and accepts non-UTF-8 arguments.

use getargs_derive::GetArgs;

#[derive(GetArgs)]
struct Cli<'a> {
    input: &'a str,
    #[arg(short, long)]
    verbose: bool,
    #[arg(short, long, default_value = "output.txt")]
    output: &'a str,
}

let cli = Cli::from_args(["input.txt", "--verbose"].into_iter()).unwrap();
assert_eq!(cli.input, "input.txt");
assert!(cli.verbose);
assert_eq!(cli.output, "output.txt");

Compared to Clap

getargs-derive implements a Clap-inspired subset of Clap's derive API for programs where Clap does not fit, such as no_std targets. It is not a drop-in replacement: Clap Compatibility lists what is shared and what is not supported.

getargs-derive Clap
no_std, no allocator yes no, requires std
Help text &'static str built at compile time built at run time
Derive API, doc comments as help yes yes
Builder API no yes
Subcommands, flatten, ValueEnum yes yes
Defaults, env fallbacks, aliases, Count flags yes yes
Relations conflicts_with, requires, required_unless_present, groups many more variants
Value validation parser functions, integer ranges, possible_values value_parser! and custom parsers
"Did you mean" suggestions yes yes
Non-UTF-8 arguments yes yes
Shell completions bash, zsh, fish (std) more shells, dynamic completion
Man pages yes (std) with clap_mangen
Colored output, terminal-width wrapping no yes
Prints help and exits no, your code decides yes, by default

Unsupported Clap attributes are rejected at compile time rather than silently ignored.

Guide

  • Attribute Reference: #[arg(...)] and #[command(...)] attributes, argument resolution and supported field types.
  • Flag Actions: SetTrue, SetFalse and Count flags.
  • Argument Aliases: hidden and visible long and short aliases.
  • Value Enums: #[derive(ValueEnum)] and #[arg(value_enum)] for arguments accepting a fixed set of values.
  • Default Values: default_value and default_value_t.
  • Environment Variables: env fallbacks, parse_with_env and the std feature.
  • Positional and Optional Arguments: positional arguments and Option<T> fields.
  • Repeated Values: repeated options, value_delimiter, positionals collecting the remaining arguments with num_args, and the Values, heapless::Vec and Vec storage options.
  • Argument Relations: conflicts_with, requires, required_unless_present and argument groups.
  • Value Validation: value_parser functions and ranges, and possible_values.
  • Parsing Modes: values starting with -, negative numbers and last positionals, and the limits imposed by getargs.
  • Flattened Structs: #[command(flatten)] to reuse the arguments of another struct.
  • Subcommands: #[derive(Subcommand)], #[command(subcommand)] fields, nested subcommands and global arguments.
  • Generated Help: the HELP and LONG_HELP constants, -h/--help, disable_help_flag, and help customization (hidden arguments, headings, ordering, extra text and wrapping).
  • Version Flag: #[command(version)], -V/--version and the VERSION/VERSION_TEXT constants.
  • Error Handling: the Error enum, its Clap-style messages and "did you mean" suggestions.
  • Shell Completions and Man Pages: the Command metadata trait, and bash, zsh and fish completion scripts and man pages with the std feature.
  • Non-UTF-8 Arguments: from_bytes and parse_bytes for raw &[u8] arguments, &[u8], &OsStr and PathBuf fields, and from_args_os with the std feature.
  • Clap Compatibility: what is shared with Clap, and what is not supported.
  • no_std Support: allocation-free parsing and the crate features.

Every guide page lists the compile-time diagnostics related to its topic.

Minimum Supported Rust Version

getargs-derive requires Rust 1.88 or newer, and is tested against it in CI.

License

Licensed under the MIT License.


Developed by Alix ANNERAUD.