pico_test_app/
pico_test_app.rs1#![allow(dead_code)]
2const HELP: &str = "\
10USAGE: app [OPTIONS] --number NUMBER INPUT
11
12OPTIONS:
13 --number NUMBER Set a number (required)
14 --opt-number NUMBER Set an optional number
15 --width WIDTH Set a width (non-zero, default 10)
16
17ARGS:
18 <INPUT> Input file
19";
20
21#[derive(Debug)]
22struct AppArgs {
23 number: u32,
24 opt_number: Option<u32>,
25 width: u32,
26 input: std::path::PathBuf,
27}
28
29fn parse_width(s: &str) -> Result<u32, String> {
30 let w = s.parse().map_err(|_| "not a number")?;
31 if w != 0 {
32 Ok(w)
33 } else {
34 Err("width must be positive".to_string())
35 }
36}
37
38fn main() {
39 let args = match parse_args() {
40 Ok(args) => args,
41 Err(err) => {
42 eprintln!("Error: {}.", err);
43 std::process::exit(1);
44 }
45 };
46 println!("{:#?}", args);
47}
48
49fn parse_args() -> Result<AppArgs, lexopt::Error> {
50 use lexopt::prelude::*;
51
52 let mut number = None;
53 let mut opt_number = None;
54 let mut width = 10;
55 let mut input = None;
56
57 let mut parser = lexopt::Parser::from_env();
58 while let Some(arg) = parser.next()? {
59 match arg {
60 Short('h') | Long("help") => {
61 print!("{}", HELP);
62 std::process::exit(0);
63 }
64 Long("number") => number = Some(parser.value()?.parse()?),
65 Long("opt-number") => opt_number = Some(parser.value()?.parse()?),
66 Long("width") => width = parser.value()?.parse_with(parse_width)?,
67 Value(path) if input.is_none() => input = Some(path.into()),
68 _ => return Err(arg.unexpected()),
69 }
70 }
71 Ok(AppArgs {
72 number: number.ok_or("missing required option --number")?,
73 opt_number,
74 width,
75 input: input.ok_or("missing required argument INPUT")?,
76 })
77}