Expand description
An argument parser that is truly zero-cost, similar to Unix’s
getopts.
§About
getargs is a low-level, efficient and versatile argument parser
that works similarly to getopts. It works by producing a stream of
options, and after each option, your code decides whether to require
and retrieve the value for the option or not.
You don’t have to declare a list of valid options up-front, so
getargs does not have to allocate space for them or spend runtime
searching for them. This also means that you have to write your own
help message, but since --help is just another flag, there are no
restrictions on what you do with it.
§Features
- Short
-fand long--flagflags - Required implicit values
-i VALUEand--implicit VALUE - Required or optional explicit values
-eVALUEand--explicit=VALUE - Positional arguments and
-- - Parse options at the beginning of the argument list, or anywhere
§Benefits
- Zero cost
- Zero copy
- Zero unsafe code
- Zero dependencies
- Zero allocation
- Simple to use yet versatile
#![no_std]-compatible- Compatible with
&strand&[u8]
§Performance
getargs has had a lot of attention put into profiling and
optimization, and on a modern machine it takes under 0.2μs to parse
a short array of 12 arguments.
In our testing, getargs is faster than every other argument
parsing library on crates.io. Its closest competitor is gumdrop,
which is only ~30% slower in the worst case, and its second-closest
competitor is getopt, which takes three times as long. Other
libraries degrade quickly; clap takes 45x longer. (This is not an
entirely fair comparison though, as clap is not just an
argument-parsing library, but an entire command-line application
framework. It is perhaps overqualified for simple tasks.)
§Quickstart
Check out the examples.
§Overview
-
Optionsis the main export of the library, and handles argument parsing. If you don’t need a step-by-step tutorial, its documentation contains everything you need to jump right in. -
Argumentis implemented for each type that can be parsed byOptions, such as&strand&[u8]. -
Optrepresents a short or long option, returned byOptions::next_opt. -
Argrepresents either an option or a positional argument, returned byOptions::next_arg. -
Errorrepresents a parsing error.
§Obtaining an Options
First, get an iterator over your arguments as &str or &[u8].
Usually, this is done by using args() or
args_os():
let args = std::env::args()
.skip(1) // remember to skip the executable name!
.collect::<Vec<_>>();On Linux, you can use the argv crate and OsStrExt to get an
iterator of &[u8] without allocating:
// As seen in the `no_alloc` example - only works on Linux due to
// the use of `OsStrExt::as_bytes`
let args = argv::iter().skip(1).map(OsStrExt::as_bytes);On other platforms, argv will leak memory, so be careful!
Then, pass the iterator to Options::new:
// ...
let mut opts = Options::new(args);§Accepting options at the start
If your command line looks like this, and does not accept options after positional arguments:
usage: command [OPTIONS] [ARGS]...then you can use Options::next_opt directly, just like classical
getargs (before 0.5.0) supported as next. The method is meant to
be called in a while let loop, like so:
// ...
let mut opts = Options::new(iter);
while let Some(opt) = opts.next_opt()? {
// read on!
}Options notably does not implement Iterator, because a for
loop borrows the iterator for the duration of the loop, which would
make it impossible to call Options::value and friends. Interior
mutability would make this possible, but it is difficult to find an
API design that does not sacrifice performance.
After each Opt, you can choose to do one of three things:
-
Call
Options::value, which will declare that the option requires a value, and return it orError::RequiresValue. -
Call
Options::value_opt, which will declare that the option may have an optional value, and return the value, if any. -
Do nothing before the next call to
next_opt, which will assume that the option should not have a value (and return anError::DoesNotRequireValueif an explicit value is found).
Options::next_opt will return Ok(None) when there are no
arguments left, or when -- is encountered. Once that happens, you
can iterate over the rest of the arguments as positional:
// ...
let mut opts = Options::new(iter);
while let Some(opt) = opts.next_opt()? {
// ...
}
for positional in opts.positionals() {
// ...
}
Here is the print example, which shows required and optional
values:
use getargs::{Opt, Options};
use std::env::args;
fn main() {
let mut args = args().skip(1).collect::<Vec<_>>();
if args.is_empty() {
args.push(String::from("--help")); // help the user out :)
}
let mut opts = Options::new(args.iter().map(String::as_str));
while let Some(opt) = opts.next_opt().expect("argument parsing error") {
match opt {
Opt::Short('h') | Opt::Long("help") => {
eprintln!(
r"Usage: print.rs [OPTIONS] [ARGS]...
This example prints all options and positional arguments passed to it.
It also includes some short and long options that have a required or
optional value.
-h, --help display this help and exit
-o, --optional consume an optional value and print the result
-r, --required consume a required value and print it
<anything else> print the flag passed"
);
return;
}
Opt::Short('o') | Opt::Long("optional") => {
eprintln!("option {:?}: {:?}", opt, opts.value_opt());
}
Opt::Short('r') | Opt::Long("required") => {
eprintln!("option {:?}: {:?}", opt, opts.value());
}
_ => eprintln!("option: {:?}", opt),
}
}
for arg in opts.positionals() {
eprintln!("positional: {:?}", arg)
}
}§Accepting options anywhere
getargs includes a utility function, Options::next_arg, that
can be used to easily accept both options and positional arguments
anywhere. This is starting to become the behavior of many modern
programs - arguments that do not begin with - or -- are counted
as positional, but option parsing still continues.
All you have to do is call next_arg instead of next_opt, and
match on Arg rather than Opt:
// ...
let mut opts = Options::new(iter);
while let Some(arg) = opts.next_arg()? {
// ...
match arg {
Arg::Short('h') | Arg::Long("help") => { /* ... */ }
Arg::Short('v') | Arg::Long("version") => { /* ... */ }
Arg::Positional(positional) => { /* ... */ }
_ => panic!("Unknown option: {}", arg)
}
}
Arg also has some utility methods, like Arg::opt and
Arg::positional.
The rest is virtually identical to parsing with next_opt.
Here is the anywhere example, which is similar to print but
uses next_arg instead of next_opt:
//! This example shows how to use the `Options::next_arg` method to
//! accept options and positional arguments anywhere.
//!
//! Try it with arguments like: `x -r hi y -ohi z -- --not-a-flag`
//!
//! You will get:
//!
//! ```text
//! positional: "x"
//! option Short('r'): Ok("hi")
//! positional: "y"
//! option Short('o'): Some("hi")
//! positional: "z"
//! positional: "--not-a-flag"
//! ```
use getargs::{Arg, Options};
use std::env::args;
fn main() {
let mut args = args().skip(1).collect::<Vec<_>>();
if args.is_empty() {
args.push(String::from("--help")); // help the user out :)
}
let mut opts = Options::new(args.iter().map(String::as_str));
while let Some(arg) = opts.next_arg().expect("argument parsing error") {
match arg {
Arg::Short('h') | Arg::Long("help") => {
eprintln!(
r"Usage: anywhere.rs [OPTIONS/ARGS]...
This example prints all options and positional arguments passed to it,
but options and positional arguments can be passed anywhere. It also
includes some short and long options that have a required or optional
value, just like print.rs.
-h, --help display this help and exit
-o, --optional consume an optional value and print the result
-r, --required consume a required value and print it
<anything else> print the flag passed"
);
return;
}
Arg::Short('o') | Arg::Long("optional") => {
eprintln!("option {:?}: {:?}", arg, opts.value_opt());
}
Arg::Short('r') | Arg::Long("required") => {
eprintln!("option {:?}: {:?}", arg, opts.value());
}
Arg::Short(_) | Arg::Long(_) => eprintln!("option: {:?}", arg),
Arg::Positional(arg) => eprintln!("positional: {:?}", arg),
}
}
}§Examples
There are other examples available on GitHub.
Structs§
- Into
Positionals - An iterator over what used to be the positional arguments of an
Options. - Options
- An argument parser.
- Positionals
- An iterator over the positional arguments of an
Options.