Skip to main content

Crate usage_argv

Crate usage_argv 

Source
Expand description

A zero-allocation argv parser for usage specs.

This crate implements the binding rules of the argv grammar: which token becomes which flag or argument, when a word selects a subcommand, and what is an error. It does so without building a command tree, without allocating, and in one pass.

It is the runtime half of a compiled parser. The tables it reads are meant to be emitted by a derive macro as static data, so that starting a parse costs nothing at all: there is no construction step to pay for, only the walk over argv.

§Shape of the API

Parsing yields Events rather than a map. A map would have to allocate, and would then have to be read back out again — whereas generated code can assign an event straight into a struct field. This is the same reason serde deserializes into your type instead of into a Value.

use usage_argv::{Arg, Command, Event, Flag, Parser};

static FORCE: Flag = Flag { key: 0, longs: &["force"], shorts: b"f", ..Flag::BOOL };
static FILE: Arg = Arg { key: 1, ..Arg::REQUIRED };
static ROOT: Command = Command {
    name: "ex",
    flags: &[&FORCE],
    args: &[&FILE],
    ..Command::EMPTY
};

let argv = ["--force", "a.txt"].map(std::ffi::OsStr::new);
let mut parser = Parser::new(&ROOT, &argv);

let mut force = false;
let mut file = None;
while let Some(event) = parser.next_event() {
    match event.expect("valid command line") {
        Event::Flag { flag, .. } if flag.key == 0 => force = true,
        Event::Arg { value, .. } => file = Some(value),
        _ => {}
    }
}
assert!(force);
assert_eq!(file, Some(&b"a.txt"[..]));

§Values are bytes

An Event carries &[u8], borrowed from argv. Converting to &str is the caller’s step (as_str), and it is the right place for the only failure a value can have: a command line that is not valid UTF-8 still parses — flags match, subcommands route — and only the values that are actually looked at can fail to convert.

Slicing an OsStr into &str pieces safely is not possible without allocating or unsafe. Bytes are what is left, and they turn out to be the honest interface anyway.

The reverse conversion is os_string_from_bytes, which lets a PathBuf field hold a filename that is not UTF-8 rather than a mangled copy of one. On Unix that is lossless and safe; on Windows, where WTF-8 makes it partial, a value that will not convert is reported. Either way this crate contains no unsafe, which a conversion that guessed would have cost.

§What this crate does not do

Only binding. Required-ness, choices, env fallback, defaults, var_min and var_max are all decided after the last token is read, and they need to know a value’s type, so they belong to the layer that owns the target struct. Keeping them out is what makes this loop small.

§Features

  • spec — a parallel tree of cold metadata (help text, choices, defaults, effects) and a writer that emits it as a usage spec. Off by default: a successful parse never reads any of it, so a CLI that only wants a parser should not compile it.
  • complete — answering a partial command line ([complete]), the shell scripts that ask ([script]), and putting one of those scripts where its shell will look for it ([install]). Installing ships with the scripts rather than behind a gate of its own: a script a CLI still has to tell its users to redirect by hand is the unfinished half of shipping one.

Re-exports§

pub use run::Run;
pub use run::RunAsync;
pub use run::RunAsyncWith;
pub use run::RunWith;

Modules§

run
Dispatch: handing a parsed command to the code that carries it out.

Macros§

__usage_needs_complete_feature
See __usage_needs_complete_feature.

Structs§

Arg
A positional argument.
BindingType
Resolved identity of a derive-generated binding type.
Command
A command: its flags, its positional arguments, and its subcommands.
Flag
A flag, addressed by any of its long or short forms.
InvalidValue
Why a value would not convert into the type its field holds.
Parser
A single-pass parse over argv.

Enums§

ArgAction
What supplying a declared flag does.
DoubleDash
How an argument relates to the -- separator.
Error
A binding failure.
Event
Something the parser bound.
UnknownFlags
What to do with a flag-like token that names no flag in scope.
ValueHint
A value’s shell-native completion class for #[usage(value_hint = ...)].

Constants§

HELP_LONG_KEY
The key --help answers to, and the one -h does.
HELP_SHORT_KEY
See HELP_LONG_KEY.
MAX_DEPTH
How deep a command tree this parser will descend.
SPEC_REQUEST
The word a tool sends to ask a binary for its own spec.
VERSION_LONG_KEY
See HELP_LONG_KEY.
VERSION_SHORT_KEY
See HELP_LONG_KEY.

Statics§

HELP_LONG
--help, which every command answers to.
HELP_SHORT
-h, which prints the shorter form.
VERSION_LONG
--version, where the CLI declared one.
VERSION_SHORT
-V, which clap also supplies.

Functions§

as_str
Interpret a value as UTF-8.
assert_unique_subcommand_names
Refuse two subcommands that answer to the same name, aliases included.
concat_args
Join groups of argument tables into one, at compile time.
concat_flags
Join groups of flag tables into one, at compile time.
find_subcommand
Resolve a subcommand by name or alias, at compile time.
is_help_flag
Whether a flag is one of the two the parser supplies rather than the CLI declaring it.
is_spec_request
Whether this argv asks for the spec rather than for the CLI to run.
is_version_arg
Whether one exact root argument selects a declared or synthesized version action.
is_version_flag
Whether a flag is one of the two the parser supplies for --version.
key_base
The high half of every key one declaration’s items get.
multicall_applet
The applet name to parse as the first word, when argv[0] is not the dispatcher.
multicall_basename
Basename of argv[0] for a multicall CLI: last path component, with a trailing .exe stripped so Windows and Unix agree.
os_string_from_bytes
Rebuild an OsString from bytes the parser handed back.
table_len
How many entries a group of tables holds in total.