hello_error/
hello-error.rs

1use lexarg_error::ErrorContext;
2
3struct Args {
4    thing: String,
5    number: u32,
6    shout: bool,
7}
8
9fn parse_args() -> Result<Args, String> {
10    #![allow(clippy::enum_glob_use)]
11    use lexarg_parser::Arg::*;
12
13    let mut thing = None;
14    let mut number = 1;
15    let mut shout = false;
16    let raw = std::env::args_os().collect::<Vec<_>>();
17    let mut parser = lexarg_parser::Parser::new(&raw);
18    let bin_name = parser
19        .next_raw()
20        .expect("nothing parsed yet so no attached lingering")
21        .expect("always at least one");
22    while let Some(arg) = parser.next_arg() {
23        match arg {
24            Short("n") | Long("number") => {
25                let value = parser.next_flag_value().ok_or_else(|| {
26                    ErrorContext::msg("missing required value")
27                        .within(arg)
28                        .to_string()
29                })?;
30                number = value
31                    .to_str()
32                    .ok_or_else(|| {
33                        ErrorContext::msg("invalid number")
34                            .unexpected(Value(value))
35                            .within(arg)
36                            .to_string()
37                    })?
38                    .parse()
39                    .map_err(|e| {
40                        ErrorContext::msg(e)
41                            .unexpected(Value(value))
42                            .within(arg)
43                            .to_string()
44                    })?;
45            }
46            Long("shout") => {
47                shout = true;
48            }
49            Value(val) if thing.is_none() => {
50                thing = Some(val.to_str().ok_or_else(|| {
51                    ErrorContext::msg("invalid string")
52                        .unexpected(arg)
53                        .to_string()
54                })?);
55            }
56            Short("h") | Long("help") => {
57                println!("Usage: hello [-n|--number=NUM] [--shout] THING");
58                std::process::exit(0);
59            }
60            _ => {
61                return Err(ErrorContext::msg("unexpected argument")
62                    .unexpected(arg)
63                    .to_string());
64            }
65        }
66    }
67
68    Ok(Args {
69        thing: thing
70            .ok_or_else(|| {
71                ErrorContext::msg("missing argument THING")
72                    .within(Value(bin_name))
73                    .to_string()
74            })?
75            .to_owned(),
76        number,
77        shout,
78    })
79}
80
81fn main() -> Result<(), String> {
82    let args = parse_args()?;
83    let mut message = format!("Hello {}", args.thing);
84    if args.shout {
85        message = message.to_uppercase();
86    }
87    for _ in 0..args.number {
88        println!("{message}");
89    }
90    Ok(())
91}