macro_rules! construct {
    ($ns:ident $(:: $con:ident)* { $($tokens:tt)* }) => { ... };
    (:: $ns:ident $(:: $con:ident)* { $($tokens:tt)* }) => { ... };
    ($ns:ident $(:: $con:ident)* ( $($tokens:tt)* )) => { ... };
    (:: $ns:ident $(:: $con:ident)* ( $($tokens:tt)* )) => { ... };
    ($first:ident , $($tokens:tt)*) => { ... };
    ($first:ident (), $($tokens:tt)*) => { ... };
    ([$first:ident $($tokens:tt)*]) => { ... };
    (@prepare $ty:tt [$($fields:tt)*] $field:ident (), $($rest:tt)*) => { ... };
    (@prepare $ty:tt [$($fields:tt)*] $field:ident () $($rest:tt)*) => { ... };
    (@prepare $ty:tt [$($fields:tt)*] $field:ident, $($rest:tt)*) => { ... };
    (@prepare $ty:tt [$($fields:tt)*] $field:ident $($rest:tt)*) => { ... };
    (@prepare [alt] [$first:ident $($fields:ident)*]) => { ... };
    (@prepare $ty:tt [$($fields:tt)*]) => { ... };
    (@make [named [$($con:tt)+]] [$($fields:ident)*]) => { ... };
    (@make [pos   [$($con:tt)+]] [$($fields:ident)*]) => { ... };
    (@make [pos] [$($fields:ident)*]) => { ... };
}
Expand description

Compose several parsers to produce a single result

Usage reference

// structs with unnamed fields:
construct!(Res(a, b, c));

// structs with named fields:
construct!(Res {a, b, c});

// enums with unnamed fields:
construct!(Ty::Res(a, b, c));

// enums with named fields:
construct!(Ty::Res {a, b, c});

// tuples:
construct!(a, b, c);

// parallel composition, tries all parsers, picks succeeding left most one:
construct!([a, b, c]);

Combinatoric usage

construct! can compose parsers sequentially or in parallel.

Sequential composition runs each parser and if all of them succeed you get a parser object of a new type back. Placeholder names for values inside construct! macro must correspond to both struct/enum names and parser names present in scope. In examples below a corresponds to a function and b corresponds to a variable name. Note parens in a(), you must to use them to indicate function parsers.

struct Res (u32, u32);
enum Ul { T { a: u32, b: u32 } }

// You can share parameters across multiple construct invocations
// if defined as functions
fn a() -> impl Parser<u32> {
    short('a').argument("N").from_str::<u32>()
}

// You can construct structs or enums with unnamed fields
fn res() -> impl Parser<Res> {
    let b = short('b').argument("n").from_str::<u32>();
    construct!(Res ( a(), b ))
}

// You can construct structs or enums with named fields
fn ult() -> impl Parser<Ul> {
    let b = short('b').argument("n").from_str::<u32>();
    construct!(Ul::T { a(), b })
}

// You can also construct simple tuples
fn tuple() -> impl Parser<(u32, u32)> {
    let b = short('b').argument("n").from_str::<u32>();
    construct!(a(), b)
}

Parallel composition picks one of several available parsers (result types must match) and returns a parser object of the same type. Similar to sequential composition you can use parsers from variables or functions:

fn b() -> impl Parser<u32> {
    short('b').argument("NUM").from_str::<u32>()
}

fn a_or_b() -> impl Parser<u32> {
    let a = short('a').argument("NUM").from_str::<u32>();
    // equivalent way of writing this would be `a.or_else(b())`
    construct!([a, b()])
}

Derive usage

bpaf_derive would combine fields of struct or enum constructors sequentially and enum variants in parallel.

// to satisfy this parser user needs to pass both -a and -b
#[derive(Debug, Clone, Bpaf)]
struct Res {
    a: u32,
    b: u32,
}

// to satisfy this parser user needs to pass one (and only one) of -a, -b, -c or -d
#[derive(Debug, Clone, Bpaf)]
enum Enumeraton {
    A { a: u32 },
    B { b: u32 },
    C { c: u32 },
    D { d: u32 },
}

// here user needs to pass either both -a AND -b or both -c and -d
#[derive(Debug, Clone, Bpaf)]
enum Ult {
    AB { a: u32, b: u32 },
    CD { c: u32, d: u32 }
}