1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//! You can construct parser at runtime without having a concrete type too

use bpaf::*;

#[derive(Debug, Clone)]
enum Value {
    Bool(bool),
    Number(usize),
    String(String),
}

fn number(name: &'static str) -> impl Parser<(String, Value)> {
    let label = name.to_string();
    long(name)
        .argument::<usize>("NUM")
        .map(move |n| (label.clone(), Value::Number(n)))
}

fn bool(name: &'static str) -> impl Parser<(String, Value)> {
    let label = name.to_string();
    long(name)
        .switch()
        .map(move |n| (label.clone(), Value::Bool(n)))
}

fn string(name: &'static str) -> impl Parser<(String, Value)> {
    let label = name.to_string();
    long(name)
        .help("this can use a help message")
        .argument::<String>("NUM")
        .map(move |n| (label.clone(), Value::String(n)))
}

fn cons<T>(acc: Box<dyn Parser<Vec<T>>>, cur: Box<dyn Parser<T>>) -> Box<dyn Parser<Vec<T>>>
where
    T: 'static,
{
    construct!(acc, cur)
        .map(|(mut acc, cur)| {
            acc.push(cur);
            acc
        })
        .boxed()
}

enum Ty {
    Bool,
    Number,
    String,
}

fn main() {
    let items = &[
        ("banana", Ty::Bool),
        ("width", Ty::Number),
        ("name", Ty::String),
    ];

    let mut parser = pure(Vec::<(String, Value)>::new()).boxed();
    for (name, ty) in items {
        parser = cons(
            parser,
            match ty {
                Ty::Bool => bool(name).boxed(),
                Ty::Number => number(name).boxed(),
                Ty::String => string(name).boxed(),
            },
        )
    }

    let options = parser.run();
    println!("{:?}", options);
}