Parser

Trait Parser 

Source
pub trait Parser<T> {
Show 19 methods // Provided methods fn many(self) -> ParseMany<Self> where Self: Sized { ... } fn collect<C>(self) -> ParseCollect<Self, C, T> where C: FromIterator<T>, Self: Sized { ... } fn some(self, message: &'static str) -> ParseSome<Self> where Self: Sized + Parser<T> { ... } fn optional(self) -> ParseOptional<Self> where Self: Sized + Parser<T> { ... } fn count(self) -> ParseCount<Self, T> where Self: Sized + Parser<T> { ... } fn last(self) -> ParseLast<Self> where Self: Sized + Parser<T> { ... } fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R> where Self: Sized + Parser<T>, F: Fn(T) -> Result<R, E>, E: ToString { ... } fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R> where Self: Sized + Parser<T>, F: Fn(T) -> R + 'static { ... } fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F> where Self: Sized + Parser<T>, F: Fn(&T) -> bool { ... } fn fallback(self, value: T) -> ParseFallback<Self, T> where Self: Sized + Parser<T> { ... } fn fallback_with<F, E>( self, fallback: F, ) -> ParseFallbackWith<T, Self, F, E> where Self: Sized + Parser<T>, F: Fn() -> Result<T, E>, E: ToString { ... } fn hide(self) -> ParseHide<Self> where Self: Sized + Parser<T> { ... } fn hide_usage(self) -> ParseUsage<Self> where Self: Sized + Parser<T> { ... } fn custom_usage<M>(self, usage: M) -> ParseUsage<Self> where M: Into<Doc>, Self: Sized + Parser<T> { ... } fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self> where Self: Sized + Parser<T> { ... } fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F> where Self: Sized + Parser<T>, F: Fn(MetaInfo<'_>) -> Doc { ... } fn to_options(self) -> OptionParser<T> where Self: Sized + Parser<T> + 'static { ... } fn run(self) -> T where Self: Sized + Parser<T> + 'static { ... } fn boxed(self) -> Box<dyn Parser<T>> where Self: Sized + Parser<T> + 'static { ... }
}
Expand description

Simple or composed argument parser

§Overview

It’s best to think of an object implementing Parser trait as a container with a value inside that is composable with other Parser containers using construct! and the only way to extract this value is by transforming it to OptionParser with to_options and running it with run. At which point you either get your value out or bpaf would generate a message describing a problem (missing argument, validation failure, user requested help, etc) and the program would exit.

Values inside can be of any type for as long as they implement Debug, Clone and there are no lifetimes other than static.

When consuming the values you can jump straight to a value that implements FromStr trait and then transform it into something that your program would use. Alternatively, you can consume either String or OsString and parse that by hand. It’s better to perform as much parsing and validation inside the Parser as possible so the program itself gets strictly typed and correct value while the user gets immediate feedback on what’s wrong with the arguments they pass.

Order of operations matters, each subsequent parser gets the output of the earlier one. Both parsers a and b would consume multiple numeric values, each less than 10, but a validates a single value and then consumes multiple of them already validated, while b first consumes and then performs validation. The former approach is usually more readable.

let a = short('a').argument::<usize>("N")
    .guard(|&a| a < 10, "`a` must be below 10")
    .many();
let b = short('b').argument::<usize>("N")
    .many()
    .guard(|bs| bs.iter().all(|&b| b < 10), "`b` must be below 10");

The same logic applies to derive API - the current type depends on the order of annotations:

#[derive(Bpaf, Debug, Clone)]
struct Simple {
    #[bpaf(argument("N"), guard(less_than_10, "`a` must be below 10"), many)]
    a: Vec<usize>,
    #[bpaf(argument("N"), many, guard(all_less_than_10, "`b` must be below 10"))]
    b: Vec<usize>,
}

For example suppose your program needs the user to specify dimensions of a rectangle, with sides being 1..20 units long and the total area must not exceed 200 units square. A parser that consumes it might look like this:

#[derive(Debug, Copy, Clone)]
struct Rectangle {
    width: u32,
    height: u32,
}

fn rectangle() -> impl Parser<Rectangle> {
    let invalid_size = "Sides of a rectangle must be 1..20 units long";
    let invalid_area = "Area of a rectangle must not exceed 200 units square";
    let width = long("width")
        .help("Width of the rectangle")
        .argument::<u32>("PX")
        .guard(|&x| 1 <= x && x <= 10, invalid_size);
    let height = long("height")
        .help("Height of the rectangle")
        .argument::<u32>("PX")
        .guard(|&x| 1 <= x && x <= 10, invalid_size);
    construct!(Rectangle { width, height })
        .guard(|&r| r.width * r.height <= 400, invalid_area)
}

§Derive specific considerations

Every method defined on this trait belongs to the postprocessing section of the field annotation. bpaf would try to figure out what chain to use for as long as there are no options changing the type: you can use fallback, fallback_with, guard, hide and group_help but not the rest of them.

#[derive(Debug, Clone, Bpaf)]
struct Options {
    // no annotation at all - `bpaf` inserts implicit `argument` and gets the right type
    number_1: u32,

    // fallback isn't changing the type so `bpaf` still handles it
    #[bpaf(fallback(42))]
    number_2: u32,

    // `bpaf` inserts implicit `argument`, `optional` and the right type
    number_3: Option<u32>,

    // fails to compile: you need to specify `argument`
    // #[bpaf(optional)]
    // number_4: Option<u32>,

    #[bpaf(argument("N"), optional)]
    number_5: Option<u32>,

    // explicit consumer and a full postprocessing chain
    #[bpaf(argument::<u32>("N"), optional)]
    number_6: Option<u32>,
}

Provided Methods§

Source

fn many(self) -> ParseMany<Self>
where Self: Sized,

Consume zero or more items from a command line and collect them into a Vec

many preserves any parsing failures and propagates them outwards, with an extra catch statement you can instead stop at the first value that failed to parse and ignore it and all the subsequent ones.

many will collect at most one result that does not consume anything from the argument list allowing using it in combination with any parsers with a fallback. After the first one, it will keep collecting the results as long as they consume something.

For derive usage bpaf would insert implicit many when the resulting type is a vector.

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    argument: Vec<u32>,
    switches: Vec<bool>,
}

pub fn options() -> OptionParser<Options> {
    let argument = long("argument")
        .help("important argument")
        .argument("ARG")
        .many();
    let switches = long("switch").help("some switch").switch().many();
    construct!(Options { argument, switches }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    /// important argument
    argument: Vec<u32>,
    /// some switch
    #[bpaf(long("switch"), switch)]
    switches: Vec<bool>,
}

fn main() {
    println!("{:?}", options().run())
}
Output

In usage lines many items are indicated with ...

$ app --help

Usage: app [--argument=ARG]... [--switch]...

Available options:
--argument=ARG
important argument
--switch
some switch
-h, --help
Prints help information

Run inner parser as many times as possible collecting all the new results First false is collected from a switch even if it is not consuming anything

$ app --argument 10 --argument 20
Options { argument: [10, 20], switches: [false] }

If there’s no matching parameters - it would produce an empty vector. Note, in case of switch parser or other parsers that can succeed without consuming anything it would capture that value so many captures the first one of those. You can use req_flag to avoid that.

$ app
Options { argument: [], switches: [false] }

For parsers that can succeed without consuming anything such as flag or switch - many only collects values as long as they produce something

$ app --switch --switch
Options { argument: [], switches: [true, true] }
§See also

some also collects results to a vector but requires at least one element to succeed, collect collects results into a FromIterator structure

Source

fn collect<C>(self) -> ParseCollect<Self, C, T>
where C: FromIterator<T>, Self: Sized,

Transform parser into a collection parser

A generic variant of many, instead of collecting into a vector it collects into any collection that implements FromIterator trait

collect preserves any parsing failures and propagates them outwards, with extra catch statement you can instead stop at the first value that failed to parse and ignore it and all the subsequent ones.

Combinatoric example
use std::collections::BTreeSet;

#[derive(Debug, Clone)]
pub struct Options {
    argument: BTreeSet<u32>,
    switches: BTreeSet<bool>,
}

pub fn options() -> OptionParser<Options> {
    let argument = long("argument")
        .help("important argument")
        .argument("ARG")
        .collect();
    let switches = long("switch").help("some switch").switch().collect();
    construct!(Options { argument, switches }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
use std::collections::BTreeSet;

#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    /// important argument
    #[bpaf(argument::<u32>("ARG"), collect)]
    argument: BTreeSet<u32>,
    /// some switch
    #[bpaf(long("switch"), switch, collect)]
    switches: BTreeSet<bool>,
}

fn main() {
    println!("{:?}", options().run())
}
Output

In usage lines collect items are indicated with ...

$ app --help

Usage: app --argument=ARG... [--switch]...

Available options:
--argument=ARG
important argument
--switch
some switch
-h, --help
Prints help information

Run inner parser as many times as possible collecting all the new results First false is collected from a switch even if it is not consuming anything

$ app --argument 10 --argument 20 --argument 20
Options { argument: {10, 20}, switches: {false} }

If there’s no matching parameters - it would produce an empty set. Note, in case of switch parser or other parsers that can succeed without consuming anything it would capture that value so many captures the first one of those. You can use req_flag to avoid that.

$ app
Options { argument: {}, switches: {false} }

For parsers that can succeed without consuming anything such as flag or switch - many only collects values as long as they produce something

$ app --switch --switch
Options { argument: {}, switches: {true} }

collect will collect at most one result that does not consume anything from the argument list allowing using it in combination of any parsers with a fallback. After the first one it will keep collecting the results as long as they consume something.

Source

fn some(self, message: &'static str) -> ParseSome<Self>
where Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec

Takes a string used as an error message if there are no specified parameters

some preserves any parsing failures and propagates them outwards, with an extra catch statement you can instead stop at the first value that failed to parse and ignore it and all the subsequent ones.

some will collect at most one result that does not consume anything from the argument list allowing using it in combination with any parsers with a fallback. After the first one, it will keep collecting the results as long as they consume something.

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    argument: Vec<u32>,
    switches: Vec<bool>,
}

pub fn options() -> OptionParser<Options> {
    let argument = long("argument")
        .help("important argument")
        .argument("ARG")
        .some("want at least one argument");
    let switches = long("switch")
        .help("some switch")
        .req_flag(true)
        .some("want at least one switch");
    construct!(Options { argument, switches }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    /// important argument
    #[bpaf(argument("ARG"), some("want at least one argument"))]
    argument: Vec<u32>,
    /// some switch
    #[bpaf(long("switch"), req_flag(true), some("want at least one switch"))]
    switches: Vec<bool>,
}

fn main() {
    println!("{:?}", options().run())
}
Output

In usage lines some items are indicated with ...

$ app --help

Usage: app --argument=ARG... --switch...

Available options:
--argument=ARG
important argument
--switch
some switch
-h, --help
Prints help information

Run inner parser as many times as possible collecting all the new results, but unlike many needs to collect at least one element to succeed

$ app --argument 10 --argument 20 --switch
Options { argument: [10, 20], switches: [true] }

With not enough parameters to satisfy both parsers at least once - it fails

$ app
Error: want at least one argument

both parsers need to succeed to create a struct

$ app --argument 10
Error: want at least one switch

For parsers that can succeed without consuming anything such as flag or switch - some only collects values as long as they produce something

$ app --switch --argument 10
Options { argument: [10], switches: [true] }
§See also

many also collects results to a vector but succeeds with no matching values. collect collects results into a FromIterator structure

Source

fn optional(self) -> ParseOptional<Self>
where Self: Sized + Parser<T>,

Turn a required argument into an optional one

optional converts any missing items into None and passes the remaining parsing failures untouched. With an extra catch statement, you can handle those failures too.

§Derive usage

By default, bpaf would automatically use optional for fields of type Option<T>, for as long as it’s not prevented from doing so by present postprocessing options. But it’s also possible to specify it explicitly.

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    version: Option<usize>,
    feature: Option<String>,
}
pub fn options() -> OptionParser<Options> {
    let version = long("version").argument("VERS").optional();
    let feature = long("feature").argument("FEAT").optional();
    construct!(Options { version, feature }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    #[bpaf(argument("VERS"))]
    version: Option<usize>,
    #[bpaf(argument("FEAT"))]
    feature: Option<String>,
}

fn main() {
    println!("{:?}", options().run())
}
Output

bpaf encases optional arguments in usage with []

$ app --help

Usage: app [--version=VERS] [--feature=FEAT]

Available options:
--version=VERS
--feature=FEAT
-h, --help
Prints help information

Missing arguments are turned into None

$ app
Options { version: None, feature: None }

Present values are Some

$ app --version 10
Options { version: Some(10), feature: None }

As usual you can specify both

$ app --version 10 --feature feat
Options { version: Some(10), feature: Some("feat") }
Source

fn count(self) -> ParseCount<Self, T>
where Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number.

When you are dealing with a parser that can succeed without consuming anything from a command line - bpaf will count first such success as well.

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    verbosity: usize,
}

pub fn options() -> OptionParser<Options> {
    let verbosity = short('v')
        .long("verbose")
        .help("Increase the verbosity level")
        .req_flag(())
        .count();

    construct!(Options { verbosity }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    /// Increase the verbosity level
    #[bpaf(short('v'), long("verbose"), req_flag(()), count)]
    verbosity: usize,
}

fn main() {
    println!("{:?}", options().run())
}
Output

In --help message req_flag look similarly to switch and flag

$ app --help

Usage: app [-v]...

Available options:
-v, --verbose
Increase the verbosity level
-h, --help
Prints help information

Since parser uses req_flag it succeeds exactly 0 times if there’s no parameters

$ app
Options { verbosity: 0 }

If it was specified - count tracks it a discards parsed values

$ app -vvv
Options { verbosity: 3 }
$ app --verbose --verbose
Options { verbosity: 2 }
Source

fn last(self) -> ParseLast<Self>
where Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value

You can use this to allow users to pick contradicting options

Combinatoric example
#[derive(Debug, Clone)]
pub enum Style {
    Intel,
    Att,
    Llvm,
}

#[derive(Debug, Clone)]
pub enum Report {
    /// Include defailed report
    Detailed,
    /// Include minimal report
    Minimal,
    /// No preferences
    Undecided,
}

#[derive(Debug, Clone)]
pub struct Options {
    style: Style,
    report: Report,
}

pub fn options() -> OptionParser<Options> {
    let intel = long("intel")
        .help("Show assembly using Intel style")
        .req_flag(Style::Intel);
    let att = long("att")
        .help("Show assembly using AT&T style")
        .req_flag(Style::Att);
    let llvm = long("llvm").help("Show llvm-ir").req_flag(Style::Llvm);
    let style = construct!([intel, att, llvm]).last();

    let detailed = long("detailed")
        .help("Include detailed report")
        .req_flag(Report::Detailed);
    let minimal = long("minimal")
        .help("Include minimal report")
        .req_flag(Report::Minimal);
    let report = construct!([detailed, minimal])
        .last()
        .fallback(Report::Undecided);

    construct!(Options { style, report }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
#[derive(Debug, Clone, Bpaf)]
#[bpaf(last)]
pub enum Style {
    /// Show assembly using Intel style
    Intel,
    /// Show assembly using AT&T style
    Att,
    /// Show llvm-ir
    Llvm,
}

#[derive(Debug, Clone, Bpaf)]
#[bpaf(last, fallback(Report::Undecided))]
pub enum Report {
    /// Include detailed report
    Detailed,
    /// Include minimal report
    Minimal,
    #[bpaf(skip)]
    /// No preferences
    Undecided,
}

#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    // external here uses explicit reference to function `style`
    // generated above
    #[bpaf(external(style))]
    style: Style,
    // here reference is implicit and derived from field name: `report`
    #[bpaf(external)]
    report: Report,
}

fn main() {
    println!("{:?}", options().run())
}
Output

In --help message last shows that inner parser can run multiple times

$ app --help

Usage: app (--intel | --att | --llvm)... [--detailed | --minimal]...

Available options:
--intel
Show assembly using Intel style
--att
Show assembly using AT&T style
--llvm
Show llvm-ir
--detailed
Include detailed report
--minimal
Include minimal report
-h, --help
Prints help information

style takes one of several possible values and last lets user to pass it several times

$ app --intel
Options { style: Intel, report: Undecided }
$ app --intel --att
Options { style: Att, report: Undecided }
$ app --intel --att --intel
Options { style: Intel, report: Undecided }

same goes with report

$ app --intel --detailed
Options { style: Intel, report: Detailed }
$ app --att --detailed --minimal
Options { style: Att, report: Minimal }
Source

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where Self: Sized + Parser<T>, F: Fn(T) -> Result<R, E>, E: ToString,

Apply a failing transformation to a contained value

Transformation preserves the present/absent state of the value: to parse an optional value you can either first try to parse it and then mark it as optional or first deal with the optionality and then parse a value wrapped in Option. In most cases the former approach is more concise.

Similarly, it is possible to parse multiple items with many or some by either parsing a single item first and then turning it into a Vec or collecting them into a Vec first and then parsing the whole vector. The former approach is more concise.

This is a most general of transforming parsers and you can express map and guard in terms of it.

Examples are a bit artificial, to parse a value from a string you can specify the type directly in the argument’s turbofish and then apply map.

§Derive usage:

parse takes a single parameter: function name to call. Function type should match parameter F used by parse in combinatoric API.

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    number: u32,
}

pub fn options() -> OptionParser<Options> {
    let number = long("number")
        .argument::<String>("N")
        // normally you'd use argument::<u32> to get a numeric
        // value and `map` to double it
        .parse::<_, _, ParseIntError>(|s| Ok(u32::from_str(&s)? * 2));
    construct!(Options { number }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
fn twice_the_num(s: String) -> Result<u32, ParseIntError> {
    Ok(u32::from_str(&s)? * 2)
}

#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    #[bpaf(argument::<String>("N"), parse(twice_the_num))]
    number: u32,
}

fn main() {
    println!("{:?}", options().run())
}
Output

parse don’t make any changes to generated --help message

$ app --help

Usage: app --number=N

Available options:
--number=N
-h, --help
Prints help information

You can use parse to apply arbitrary failing transformation to any input. For example here --number takes a numerical value and doubles it

$ app --number 10
Options { number: 20 }

But if function inside the parser fails - user will get the error back unless it’s handled in some other way

$ app --number ten
Error: couldn't parse ten: invalid digit found in string
Source

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where Self: Sized + Parser<T>, F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value

A common case of the parse method, exists mostly for convenience.

§Derive usage:

The map takes a single parameter: function name to call. This function should transform the value produced by the parser into a new value of the same or different type.

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    number: u32,
}
pub fn options() -> OptionParser<Options> {
    let number = long("number").argument::<u32>("N").map(|x| x * 2);
    construct!(Options { number }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
fn twice_the_num(n: u32) -> u32 {
    n * 2
}

#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    #[bpaf(argument::<u32>("N"), map(twice_the_num))]
    number: u32,
}

fn main() {
    println!("{:?}", options().run())
}
Output

map don’t make any changes to generated --help message

You can use map to apply arbitrary pure transformation to any input. Here --number takes a numerical value and doubles it

$ app --number 10
Options { number: 20 }

But if function inside the parser fails - user will get the error back unless it’s handled in some way. In fact here execution never reaches map function - argument tries to parse ten as a number, fails and reports the error

$ app --number ten
Error: couldn't parse ten: invalid digit found in string
Source

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where Self: Sized + Parser<T>, F: Fn(&T) -> bool,

Validate or fail with a message

If the value doesn’t satisfy the constraint - the parser fails with the specified error message.

§Derive usage

Derive variant of the guard takes a function name instead of a closure, mostly to keep things clean. The second argument can be either a string literal or a constant name for a static str.

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    number: u32,
}

pub fn options() -> OptionParser<Options> {
    let number = long("number").argument::<u32>("N").guard(
        |n| *n <= 10,
        "Values greater than 10 are only available in the DLC pack!",
    );
    construct!(Options { number }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
fn dlc_check(number: &u32) -> bool {
    *number <= 10
}

const DLC_NEEDED: &str = "Values greater than 10 are only available in the DLC pack!";

#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    #[bpaf(argument("N"), guard(dlc_check, DLC_NEEDED))]
    number: u32,
}

fn main() {
    println!("{:?}", options().run())
}
Output

guard don’t make any changes to generated --help message

$ app --help

Usage: app --number=N

Available options:
--number=N
-h, --help
Prints help information

You can use guard to set boundary limits or perform other checks on parsed values. Parser accepts numbers below 10

$ app --number 5
Options { number: 5 }

And fails with the error message on higher values:

$ app --number 11
Error: 11: Values greater than 10 are only available in the DLC pack!

But if function inside the parser fails - user will get the error back unless it’s handled in some way

$ app --number ten
Error: couldn't parse ten: invalid digit found in string
Source

fn fallback(self, value: T) -> ParseFallback<Self, T>
where Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line

Parser would still fail if the value is present but failure comes from some transformation

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    jobs: usize,
}

pub fn options() -> OptionParser<Options> {
    let jobs = long("jobs")
        .help("Number of jobs")
        .argument("JOBS")
        .fallback(42)
        .display_fallback();
    construct!(Options { jobs }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
#[allow(dead_code)]
pub struct Options {
    /// Number of jobs
    #[bpaf(argument("JOBS"), fallback(42), display_fallback)]
    jobs: usize,
}

fn main() {
    println!("{:?}", options().run())
}
Output

fallback changes parser to fallback to a default value used when argument is not specified

$ app
Options { jobs: 42 }

If value is present - fallback value is ignored

$ app --jobs 10
Options { jobs: 10 }

Parsing errors are preserved and presented to the user

$ app --jobs ten
Error: couldn't parse ten: invalid digit found in string

With display_fallback, debug_fallback, and format_fallback, you can make it so the default value is visible in the --help output.

$ app --help

Usage: app [--jobs=JOBS]

Available options:
--jobs=JOBS
Number of jobs
[default: 42]
-h, --help
Prints help information

§See also

fallback_with would allow to try to fallback to a value that comes from a failing computation such as reading a file. By default, the fallback value will not be shown in the --help output; you can change that by using display_fallback, debug_fallback, or format_fallback.

Source

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where Self: Sized + Parser<T>, F: Fn() -> Result<T, E>, E: ToString,

Use value produced by this function as default if the value isn’t present

Would still fail if the value is present but failure comes from some earlier transformation

Combinatoric example
fn try_to_get_version() -> Result<usize, &'static str> {
    Ok(42)
}

#[derive(Debug, Clone)]
pub struct Options {
    version: usize,
}

pub fn options() -> OptionParser<Options> {
    let version = long("version")
        .help("Specify protocol version")
        .argument("VERS")
        .fallback_with(try_to_get_version)
        .display_fallback();
    construct!(Options { version }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
fn try_to_get_version() -> Result<usize, &'static str> {
    Ok(42)
}

#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    #[bpaf(argument("VERS"), fallback_with(try_to_get_version), display_fallback)]
    /// Specify protocol version
    version: usize,
}

fn main() {
    println!("{:?}", options().run())
}
Output

fallback_with changes parser to fallback to a value that comes from a potentially failing computation when argument is not specified

$ app
Options { version: 42 }

If value is present - fallback value is ignored

$ app --version 10
Options { version: 10 }

Parsing errors are preserved and presented to the user

$ app --version ten
Error: couldn't parse ten: invalid digit found in string

bpaf encases parsers with fallback value of some sort in usage with []

$ app --help

Usage: app [--version=VERS]

Available options:
--version=VERS
Specify protocol version
[default: 42]
-h, --help
Prints help information

§See also

fallback implements similar logic expect that failures aren’t expected. By default, the fallback value will not be shown in the --help output; you can change that by using display_fallback, debug_fallback, or format_fallback.

Source

fn hide(self) -> ParseHide<Self>
where Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation

Best used for optional parsers or parsers with a defined fallback, usually for implementing backward compatibility or hidden aliases

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    argument: u32,
    switch: bool,
}

pub fn options() -> OptionParser<Options> {
    let argument = long("argument")
        .help("important argument")
        .argument("ARG")
        .fallback(30);
    let switch = long("switch").help("secret switch").switch().hide();
    construct!(Options { argument, switch }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    /// important argument
    #[bpaf(fallback(30))]
    argument: u32,
    /// secret switch
    #[bpaf(hide)]
    switch: bool,
}

fn main() {
    println!("{:?}", options().run())
}
Output

hide removes the inner parser from any help or autocompletion logic

$ app --help

Usage: app [--argument=ARG]

Available options:
--argument=ARG
important argument
-h, --help
Prints help information

But doesn’t change the parsing behavior in any way otherwise

$ app --argument 32
Options { argument: 32, switch: false }
$ app --argument 42 --switch
Options { argument: 42, switch: true }
Source

fn hide_usage(self) -> ParseUsage<Self>
where Self: Sized + Parser<T>,

Ignore this parser when generating a usage line

Parsers hidden from usage will still show up in the available arguments list. Best used on optional things that augment the main application functionality but not define it. Alternatively, you can use custom_usage to replace a single option or a group of them with some other text.

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    argument: u32,
    switch: bool,
}

pub fn options() -> OptionParser<Options> {
    let argument = long("argument")
        .help("important argument")
        .argument("ARG")
        .fallback(30);
    let switch = long("switch")
        .help("not that important switch")
        .switch()
        .hide_usage();
    construct!(Options { argument, switch }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
#[allow(dead_code)]
#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    /// important argument
    #[bpaf(fallback(30))]
    argument: u32,
    /// not that important switch
    #[bpaf(hide_usage)]
    switch: bool,
}

fn main() {
    println!("{:?}", options().run())
}
Output

hide_usage hides the inner parser from the generated usage line, but not from the rest of the help or completion

$ app --help

Usage: app [--argument=ARG]

Available options:
--argument=ARG
important argument
--switch
not that important switch
-h, --help
Prints help information

But doesn’t change the parsing behavior in any way otherwise

$ app --argument 32
Options { argument: 32, switch: false }
$ app --argument 32 --switch
Options { argument: 32, switch: true }
Source

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where M: Into<Doc>, Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    binary: Option<String>,
    package: Option<String>,
}

pub fn options() -> OptionParser<Options> {
    let binary = short('b')
        .long("binary")
        .help("Binary to run")
        .argument("BIN")
        .optional()
        .custom_usage(&[
            ("--binary", Style::Literal),
            ("=", Style::Text),
            ("BINARY", Style::Metavar),
        ]);

    let package = short('p')
        .long("package")
        .help("Package to check")
        .argument("PACKAGE")
        .optional();

    construct!(Options { binary, package }).to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
const BINARY_USAGE: &[(&str, Style)] = &[
    ("--binary", Style::Literal),
    ("=", Style::Text),
    ("BINARY", Style::Metavar),
];

#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    /// Binary to run
    #[bpaf(short, long, argument("BIN"), custom_usage(BINARY_USAGE))]
    binary: Option<String>,

    /// Package to check
    #[bpaf(short, long, argument("PACKAGE"))]
    package: Option<String>,
}

fn main() {
    println!("{:?}", options().run())
}
Output

custom_usage changes how parser shows up in the “Usage” section of generated --help, note lack of [], long name instead of a short one and different metavariable value

$ app --help

Usage: app --binary=BINARY [-p=PACKAGE]

Available options:
-b, --binary=BIN
Binary to run
-p, --package=PACKAGE
Package to check
-h, --help
Prints help information

Parsing behavior stays unchanged

$ app --binary cargo-asm --package cargo-show-asm
Options { binary: Some("cargo-asm"), package: Some("cargo-show-asm") }
Source

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where Self: Sized + Parser<T>,

Attach a help message to a complex parser

bpaf inserts the group help message before the block with all the fields from the inner parser and an empty line after the block.

Combinatoric example
#[derive(Debug, Clone)]
pub struct Rectangle {
    width: u32,
    height: u32,
}

#[derive(Debug, Clone)]
pub struct Options {
    argument: u32,
    rectangle: Rectangle,
}

pub fn options() -> OptionParser<Options> {
    let argument = long("argument")
        .help("important argument")
        .argument("ARG")
        .fallback(30);

    let width = long("width")
        .help("Width of the rectangle")
        .argument("W")
        .fallback(10);
    let height = long("height")
        .help("Height of the rectangle")
        .argument("H")
        .fallback(10);
    let rectangle = construct!(Rectangle { width, height }).group_help("Takes a rectangle");

    construct!(Options {
        argument,
        rectangle
    })
    .to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
#[derive(Debug, Clone, Bpaf)]
pub struct Rectangle {
    /// Width of the rectangle
    #[bpaf(argument("W"), fallback(10))]
    width: u32,
    /// Height of the rectangle
    #[bpaf(argument("H"), fallback(10))]
    height: u32,
}

#[derive(Debug, Clone, Bpaf)]
#[bpaf(options)]
pub struct Options {
    /// important argument
    #[bpaf(fallback(30))]
    argument: u32,
    /// secret switch
    #[bpaf(external, group_help("Takes a rectangle"))]
    rectangle: Rectangle,
}

fn main() {
    println!("{:?}", options().run())
}
Output

group_help adds extra decoration for the inner group in --help message

$ app --help

Usage: app [--argument=ARG] [--width=W] [--height=H]

Takes a rectangle
--width=W
Width of the rectangle
--height=H
Height of the rectangle

Available options:
--argument=ARG
important argument
-h, --help
Prints help information

And doesn’t change the parsing behavior in any way

$ app --argument 32 --width 20 --height 13
Options { argument: 32, rectangle: Rectangle { width: 20, height: 13 } }
Source

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where Self: Sized + Parser<T>, F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo

use bpaf::doc::*;
use bpaf::*;
#[derive(Debug, Clone)]
pub struct Rectangle {
    width: u32,
    height: u32,
}

#[derive(Debug, Clone)]
pub struct Options {
    argument: u32,
    rectangle: Rectangle,
}

fn generate_rectangle_help(meta: MetaInfo) -> Doc {
    let mut buf = Doc::default();
    buf.text("The app takes a rectangle defined by width and height\n\nYou can customize the screen size using ");
    buf.meta(meta, true);
    buf.text(" parameters");
    buf
}

pub fn options() -> OptionParser<Options> {
    let argument = long("argument")
        .help("important argument")
        .argument("ARG")
        .fallback(30);
    let width = long("width")
        .help("Width of the rectangle")
        .argument("W")
        .fallback(10);
    let height = long("height")
        .help("Height of the rectangle")
        .argument("H")
        .fallback(10);
    let rectangle =
        construct!(Rectangle { width, height }).with_group_help(generate_rectangle_help);

    construct!(Options {
        argument,
        rectangle
    })
    .to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Output

with_group_help lets you write longer description for group of options that can also refer to those options. Similar to group_help encased optios are separated from the rest by a blank line.

Invoking help with a single --help flag renders shot(er) version of the help message that contanis only the first paragraph for each block:

$ app --help

Usage: app [--argument=ARG] [--width=W] [--height=H]

The app takes a rectangle defined by width and height
You can customize the screen size using [--width=W] [--height=H] parameters
--width=W
Width of the rectangle
--height=H
Height of the rectangle

Available options:
--argument=ARG
important argument
-h, --help
Prints help information

Invoking help with double --help --help flag renders the full help message with all the descriptions added

$ app --help --help

Usage: app [--argument=ARG] [--width=W] [--height=H]

The app takes a rectangle defined by width and height
You can customize the screen size using [--width=W] [--height=H] parameters
--width=W
Width of the rectangle
--height=H
Height of the rectangle

Available options:
--argument=ARG
important argument
-h, --help
Prints help information

Other than rendering the help message that there’s no interactions with other parsers

$ app --width 120 --height 11
Options { argument: 30, rectangle: Rectangle { width: 120, height: 11 } }
$ app --argument 12
Options { argument: 12, rectangle: Rectangle { width: 10, height: 10 } }
Source

fn to_options(self) -> OptionParser<T>
where Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it

§Derive usage

Add a top-level options annotation to generate OptionParser instead of default Parser.

In addition to options annotation, you can also specify either version or version(value) annotation. The former uses version from cargo, later uses the specified value which should be an expression of type &'static str, see version.

Combinatoric example
#[derive(Debug, Clone)]
pub struct Options {
    argument: u32,
}

pub fn options() -> OptionParser<Options> {
    let argument = short('i').argument::<u32>("ARG");
    construct!(Options { argument })
        .to_options()
        .version("3.1415")
        .descr("This is a short description")
        .header("It can contain multiple blocks, this block goes before options")
        .footer("This one goes after")
}

fn main() {
    println!("{:?}", options().run())
}
Derive example
#[derive(Debug, Clone, Bpaf)]
#[bpaf(options, version("3.1415"))]
/// This is a short description
///
///
/// It can contain multiple blocks, this block goes before options
///
///
/// This one goes after
pub struct Options {
    #[bpaf(short('i'))]
    argument: u32,
}

fn main() {
    println!("{:?}", options().run())
}
Output

In addition to all the arguments specified by user bpaf adds a few more. One of them is --help:

$ app --help

This is a short description

Usage: app -i=ARG

It can contain multiple blocks, this block goes before options

Available options:
-i=ARG
-h, --help
Prints help information
-V, --version
Prints version information

This one goes after

The other one is --version - passing a string literal or something like env!("CARGO_PKG_VERSION") to get version from cargo directly usually works

$ app --version

Version: 3.1415

Other than that bpaf tries its best to provide a helpful error messages

$ app
Error: expected -i=ARG, pass --help for usage information

And if all parsers are satisfied run produces the result

$ app -i 10
Options { argument: 10 }
§See also

There’s some methods implemented on OptionParser directly to customize the appearance

Source

fn run(self) -> T
where Self: Sized + Parser<T> + 'static,

Finalize and run the parser

Generally, you’d want to use Parser::to_options to finalize the parser and OptionParser::run, but this also works for simple cases:

fn main() {
    let name = short('n').long("name").argument::<String>("USER").run();
    // do things with name
}
Source

fn boxed(self) -> Box<dyn Parser<T>>
where Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser

The boxed parser doesn’t expose internal representation in its type and allows to return of different parsers in different conditional branches

You can create it with a single argument construct macro or by using boxed annotation


pub fn options() -> OptionParser<f64> {
    let miles = long("distance")
        .help("distance in miles")
        .argument::<f64>("MILES")
        .map(|d| d * 1.609344);

    let km = long("distance")
        .help("distance in km")
        .argument::<f64>("KM");

    // suppose this is reading from config fule
    let use_metric = true;

    // without use of `boxed` here branches have different types so it won't typecheck
    // boxed make it so branches have the same type as long as they return the same type
    let distance = if use_metric {
        km.boxed()
    } else {
        miles.boxed()
    };

    distance.to_options()
}

fn main() {
    println!("{:?}", options().run())
}
Output

It is also possible to make dynamic choice about the parsers. This example defines two parsers for distance - imperial and metric and picks one from some source available at runtime only.

Help message will contain only one parser

$ app --help

Usage: app --distance=KM

Available options:
--distance=KM
distance in km
-h, --help
Prints help information

and only one parser will produce a result

$ app --distance 10
10.0

Trait Implementations§

Source§

impl<T> Parser<T> for Box<dyn Parser<T>>

Source§

fn many(self) -> ParseMany<Self>
where Self: Sized,

Consume zero or more items from a command line and collect them into a Vec Read more
Source§

fn collect<C>(self) -> ParseCollect<Self, C, T>
where C: FromIterator<T>, Self: Sized,

Transform parser into a collection parser Read more
Source§

fn some(self, message: &'static str) -> ParseSome<Self>
where Self: Sized + Parser<T>,

Consume one or more items from a command line and collect them into a Vec Read more
Source§

fn optional(self) -> ParseOptional<Self>
where Self: Sized + Parser<T>,

Turn a required argument into an optional one Read more
Source§

fn count(self) -> ParseCount<Self, T>
where Self: Sized + Parser<T>,

Count how many times the inner parser succeeds, and return that number. Read more
Source§

fn last(self) -> ParseLast<Self>
where Self: Sized + Parser<T>,

Apply the inner parser as many times as it succeeds, return the last value Read more
Source§

fn parse<F, R, E>(self, f: F) -> ParseWith<T, Self, F, E, R>
where Self: Sized + Parser<T>, F: Fn(T) -> Result<R, E>, E: ToString,

Apply a failing transformation to a contained value Read more
Source§

fn map<F, R>(self, map: F) -> ParseMap<T, Self, F, R>
where Self: Sized + Parser<T>, F: Fn(T) -> R + 'static,

Apply a pure transformation to a contained value Read more
Source§

fn guard<F>(self, check: F, message: &'static str) -> ParseGuard<Self, F>
where Self: Sized + Parser<T>, F: Fn(&T) -> bool,

Validate or fail with a message Read more
Source§

fn fallback(self, value: T) -> ParseFallback<Self, T>
where Self: Sized + Parser<T>,

Use this value as default if the value isn’t present on a command line Read more
Source§

fn fallback_with<F, E>(self, fallback: F) -> ParseFallbackWith<T, Self, F, E>
where Self: Sized + Parser<T>, F: Fn() -> Result<T, E>, E: ToString,

Use value produced by this function as default if the value isn’t present Read more
Source§

fn hide(self) -> ParseHide<Self>
where Self: Sized + Parser<T>,

Ignore this parser during any sort of help generation Read more
Source§

fn hide_usage(self) -> ParseUsage<Self>
where Self: Sized + Parser<T>,

Ignore this parser when generating a usage line Read more
Source§

fn custom_usage<M>(self, usage: M) -> ParseUsage<Self>
where M: Into<Doc>, Self: Sized + Parser<T>,

Customize how this parser looks like in the usage line Read more
Source§

fn group_help<M: Into<Doc>>(self, message: M) -> ParseGroupHelp<Self>
where Self: Sized + Parser<T>,

Attach a help message to a complex parser Read more
Source§

fn with_group_help<F>(self, f: F) -> ParseWithGroupHelp<Self, F>
where Self: Sized + Parser<T>, F: Fn(MetaInfo<'_>) -> Doc,

Make a help message for a complex parser from its MetaInfo Read more
Source§

fn to_options(self) -> OptionParser<T>
where Self: Sized + Parser<T> + 'static,

Transform Parser into OptionParser to get ready to run it Read more
Source§

fn run(self) -> T
where Self: Sized + Parser<T> + 'static,

Finalize and run the parser Read more
Source§

fn boxed(self) -> Box<dyn Parser<T>>
where Self: Sized + Parser<T> + 'static,

Create a boxed representation for a parser Read more

Implementations on Foreign Types§

Source§

impl<T> Parser<T> for Box<dyn Parser<T>>

Implementors§

Source§

impl<P, T> Parser<T> for ParseAdjacent<P>
where P: Parser<T> + Sized,

Source§

impl<P, T> Parser<T> for ParseFallback<P, T>
where P: Parser<T>, T: Clone,

Source§

impl<P, T, F, R> Parser<R> for ParseMap<T, P, F, R>
where F: Fn(T) -> R, P: Parser<T> + Sized,

Source§

impl<T> Parser<T> for ParseAny<T>

Source§

impl<T> Parser<T> for ParseArgument<T>
where T: FromStr + 'static, <T as FromStr>::Err: Display,

Source§

impl<T> Parser<T> for ParseCommand<T>

Source§

impl<T> Parser<T> for ParsePositional<T>
where T: FromStr + 'static, <T as FromStr>::Err: Display,

Source§

impl<T> Parser<T> for ParseFail<T>

Source§

impl<T> Parser<T> for ParseOrElse<T>

Source§

impl<T, C, P> Parser<C> for ParseCollect<P, C, T>
where P: Parser<T>, C: FromIterator<T>,

Source§

impl<T, P> Parser<Option<T>> for ParseOptional<P>
where P: Parser<T>,

Source§

impl<T, P> Parser<usize> for ParseCount<P, T>
where P: Parser<T>,

Source§

impl<T, P> Parser<Vec<T>> for ParseMany<P>
where P: Parser<T>,

Source§

impl<T, P> Parser<Vec<T>> for ParseSome<P>
where P: Parser<T>,

Source§

impl<T, P> Parser<T> for ParseCon<P>
where P: Fn(bool, &mut State) -> Result<T, Error>,

Source§

impl<T, P> Parser<T> for ParseGroupHelp<P>
where P: Parser<T>,

Source§

impl<T, P> Parser<T> for ParseHide<P>
where P: Parser<T>,

Source§

impl<T, P> Parser<T> for ParseLast<P>
where P: Parser<T>,

Source§

impl<T, P> Parser<T> for ParseUsage<P>
where P: Parser<T>,

Source§

impl<T, P, F> Parser<T> for ParseGuard<P, F>
where P: Parser<T>, F: Fn(&T) -> bool,

Source§

impl<T, P, F> Parser<T> for ParseWithGroupHelp<P, F>
where P: Parser<T>, F: Fn(MetaInfo<'_>) -> Doc,

Source§

impl<T, P, F, E> Parser<T> for ParseFallbackWith<T, P, F, E>
where P: Parser<T>, F: Fn() -> Result<T, E>, E: ToString,

Source§

impl<T, P, F, E, R> Parser<R> for ParseWith<T, P, F, E, R>
where P: Parser<T>, F: Fn(T) -> Result<R, E>, E: ToString,

Source§

impl<T: Clone + 'static> Parser<T> for ParseFlag<T>

Source§

impl<T: Clone + 'static> Parser<T> for ParsePure<T>

Source§

impl<T: Clone + 'static, F: Fn() -> Result<T, E>, E: ToString> Parser<T> for ParsePureWith<T, F, E>