pound
a low-footprint, derive-first cli parser for rust.
the derive emits a flat &'static description of your command and one non-generic
engine interprets it — so you get familiar derive ergonomics, almost no compile-time
overhead, and nothing pulled in at runtime.
install
[]
= "0.1"
the basics
field shape carries meaning, so most fields need no attribute:
| field type | meaning |
|---|---|
bool |
flag — present means true |
T |
required positional |
Option<T> |
optional positional |
Vec<T> |
repeatable / variadic |
#[pound(short)] and #[pound(long)] promote any of these to a named option.
use Parse;
/// fetch urls to disk
subcommands
enum as the top-level command
derive Parse on an enum and each variant becomes a subcommand. struct variants
carry the subcommand's own flags and positionals:
use Parse;
/// a small package manager
pkg init --force
pkg add serde https://crates.io/crates/serde -f
global options + subcommand field
a struct can carry global flags and delegate the rest of the command line to a
subcommand enum via #[pound(subcommand)]:
tool --verbose build --release
tool --log debug clean
make the subcommand optional with Option<T>:
nested subcommands
enum variants can themselves carry a #[pound(subcommand)] field, nesting as
deep as you need:
hidden subcommands
annotate a variant with #[pound(hidden)] to accept it without listing it in help:
value enums
#[derive(ValueEnum)] turns a unit enum into a FromArg type. variants are
accepted as kebab-case strings and the valid choices appear automatically in help
text and error messages:
use ;
$ run --level bogus
error: invalid value 'bogus' for --level [possible values: quiet, normal, trace]
mutually exclusive options
group = "name" puts flags into a named set. by default the group is optional
(at most one). add required_group = "name" at the item level to require exactly one:
pick --fast ✓
pick ✗ error: one of --fast / --slow is required
pick --fast --slow ✗ error: --fast conflicts with --slow
pairwise conflicts
for a one-off conflict without a named group, use conflicts_with = "field":
trailing arguments
#[pound(trailing)] collects everything after -- into a Vec<String>:
custom value types
implement FromArg for any type you want to parse directly from the command line:
use ;
;
attribute reference
item attributes (struct or enum)
| attribute | meaning |
|---|---|
name = "str" |
command name in help/usage (defaults to the type name, lowercased) |
version = "str" |
version shown by -V / --version |
required_group = "g" |
exactly one flag in group g must be provided |
field attributes
| attribute | meaning |
|---|---|
short |
short flag (-f from field name, or = 'x' to override) |
long |
long flag (--field-name, or = "name" to override) |
positional |
force positional parsing (usually inferred from the type) |
trailing |
collect everything after -- into a Vec<String> |
count |
count repeated flags into a uN (-vvv → 3) |
default = "str" |
default value, parsed the same way as a user-supplied string |
value_name = "str" |
placeholder shown in usage (<PATH> instead of <output>) |
help = "str" |
override the doc comment for this field's help line |
group = "name" |
add to a named mutually-exclusive group |
conflicts_with = "f" |
this flag may not appear alongside field f |
hidden |
accept the flag/argument but omit it from help |
subcommand |
delegate remaining args to this field's Parse enum |
enum variant attributes
| attribute | meaning |
|---|---|
name = "str" |
override the subcommand name |
hidden |
accept the command but hide it from help |
going without the derive
you can hand-build a CommandSpec and impl Parse yourself — useful for
dynamic or programmatic command trees. see pound/tests/cli.rs for a full
worked example.
features
| feature | default | description |
|---|---|---|
derive |
yes | enables #[derive(Parse)] and #[derive(ValueEnum)] |
help |
yes | bakes doc-comment help text in and enables the formatter; without it, -h shows a bare usage line |
disable both with default-features = false for the leanest possible binary.
dev
the dev environment is a nix flake. nix develop gives the toolchain,
nix develop .#fmt formats the tree (nightly rustfmt + taplo) on entry.
license
EUPL-1.2