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 [Event]s 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 ;
static FORCE: Flag = Flag ;
static FILE: Arg = Arg ;
static ROOT: Command = Command ;
let argv = .map;
let mut parser = new;
let mut force = false;
let mut file = None;
while let Some = parser.next_event
assert!;
assert_eq!;
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.