|
1 | | -use clap::builder::TypedValueParser as _; |
2 | | -use clap::Args; |
3 | 1 | use clap::Parser; |
4 | | -use std::error::Error; |
| 2 | + |
| 3 | +mod builtin; |
| 4 | +mod fn_parser; |
| 5 | +mod foreign_crate; |
| 6 | +mod implicit; |
5 | 7 |
|
6 | 8 | #[derive(Parser, Debug)] // requires `derive` feature |
7 | 9 | #[command(term_width = 0)] // Just to make testing across clap features easier |
8 | 10 | enum Cli { |
9 | | - Implicit(ImplicitParsers), |
10 | | - Builtin(BuiltInParsers), |
11 | | - FnParser(FnParser), |
12 | | -} |
13 | | - |
14 | | -#[derive(Args, Debug)] |
15 | | -struct ImplicitParsers { |
16 | | - /// Implicitly using `std::str::FromStr` |
17 | | - #[arg(short = 'O')] |
18 | | - optimization: Option<usize>, |
19 | | - |
20 | | - /// Allow invalid UTF-8 paths |
21 | | - #[arg(short = 'I', value_name = "DIR", value_hint = clap::ValueHint::DirPath)] |
22 | | - include: Option<std::path::PathBuf>, |
23 | | - |
24 | | - /// Handle IP addresses |
25 | | - #[arg(long)] |
26 | | - bind: Option<std::net::IpAddr>, |
27 | | - |
28 | | - /// Allow human-readable durations |
29 | | - #[arg(long)] |
30 | | - sleep: Option<jiff::SignedDuration>, |
31 | | -} |
32 | | - |
33 | | -#[derive(Args, Debug)] |
34 | | -struct BuiltInParsers { |
35 | | - /// Support for discrete numbers |
36 | | - #[arg( |
37 | | - long, |
38 | | - default_value_t = 22, |
39 | | - value_parser = clap::builder::PossibleValuesParser::new(["22", "80"]) |
40 | | - .map(|s| s.parse::<usize>().unwrap()), |
41 | | - )] |
42 | | - port: usize, |
43 | | - |
44 | | - /// Support enums from a foreign crate that don't implement `ValueEnum` |
45 | | - #[arg( |
46 | | - long, |
47 | | - default_value_t = foreign_crate::LogLevel::Info, |
48 | | - value_parser = clap::builder::PossibleValuesParser::new(["trace", "debug", "info", "warn", "error"]) |
49 | | - .map(|s| s.parse::<foreign_crate::LogLevel>().unwrap()), |
50 | | - )] |
51 | | - log_level: foreign_crate::LogLevel, |
52 | | -} |
53 | | - |
54 | | -#[derive(Args, Debug)] |
55 | | -struct FnParser { |
56 | | - /// Hand-written parser for tuples |
57 | | - #[arg(short = 'D', value_parser = parse_key_val::<String, i32>)] |
58 | | - defines: Vec<(String, i32)>, |
59 | | -} |
60 | | - |
61 | | -/// Parse a single key-value pair |
62 | | -fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error + Send + Sync + 'static>> |
63 | | -where |
64 | | - T: std::str::FromStr, |
65 | | - T::Err: Error + Send + Sync + 'static, |
66 | | - U: std::str::FromStr, |
67 | | - U::Err: Error + Send + Sync + 'static, |
68 | | -{ |
69 | | - let pos = s |
70 | | - .find('=') |
71 | | - .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{s}`"))?; |
72 | | - Ok((s[..pos].parse()?, s[pos + 1..].parse()?)) |
73 | | -} |
74 | | - |
75 | | -mod foreign_crate { |
76 | | - #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
77 | | - pub(crate) enum LogLevel { |
78 | | - Trace, |
79 | | - Debug, |
80 | | - Info, |
81 | | - Warn, |
82 | | - Error, |
83 | | - } |
84 | | - |
85 | | - impl std::fmt::Display for LogLevel { |
86 | | - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
87 | | - let s = match self { |
88 | | - Self::Trace => "trace", |
89 | | - Self::Debug => "debug", |
90 | | - Self::Info => "info", |
91 | | - Self::Warn => "warn", |
92 | | - Self::Error => "error", |
93 | | - }; |
94 | | - s.fmt(f) |
95 | | - } |
96 | | - } |
97 | | - impl std::str::FromStr for LogLevel { |
98 | | - type Err = String; |
99 | | - |
100 | | - fn from_str(s: &str) -> Result<Self, Self::Err> { |
101 | | - match s { |
102 | | - "trace" => Ok(Self::Trace), |
103 | | - "debug" => Ok(Self::Debug), |
104 | | - "info" => Ok(Self::Info), |
105 | | - "warn" => Ok(Self::Warn), |
106 | | - "error" => Ok(Self::Error), |
107 | | - _ => Err(format!("Unknown log level: {s}")), |
108 | | - } |
109 | | - } |
110 | | - } |
| 11 | + Implicit(implicit::ImplicitParsers), |
| 12 | + Builtin(builtin::BuiltInParsers), |
| 13 | + FnParser(fn_parser::FnParser), |
111 | 14 | } |
112 | 15 |
|
113 | 16 | fn main() { |
|
0 commit comments