1use std::marker::PhantomData;
2
3#[macro_export]
4macro_rules! read_args_with_version {
5 ($ty:ty) => {{
6 struct VersionProvider;
7 impl $crate::AppVersionProvider for VersionProvider {
8 fn version() -> &'static str {
9 env!("CARGO_PKG_VERSION")
10 }
11 }
12
13 ::argh::from_env::<$crate::ArgsOrVersion<$ty, VersionProvider>>().app
14 }};
15}
16
17pub trait AppVersionProvider {
18 fn version() -> &'static str;
19}
20
21pub struct ArgsOrVersion<T: argh::FromArgs, V> {
22 pub app: T,
23 _version_marker: PhantomData<V>,
24}
25
26impl<T: argh::FromArgs, V: AppVersionProvider> argh::TopLevelCommand for ArgsOrVersion<T, V> {}
27
28impl<T: argh::FromArgs, V: AppVersionProvider> argh::FromArgs for ArgsOrVersion<T, V> {
29 fn from_args(command_name: &[&str], args: &[&str]) -> Result<Self, argh::EarlyExit> {
30 #[derive(argh::FromArgs)]
32 struct Version {
33 #[argh(switch, short = 'v')]
35 pub version: bool,
36 }
37
38 match Version::from_args(command_name, args) {
39 Ok(v) if v.version => Err(argh::EarlyExit {
40 output: format!("{} {}", command_name.first().unwrap_or(&""), V::version()),
41 status: Ok(()),
42 }),
43 Err(exit) if exit.status.is_ok() => {
44 let help = match T::from_args(command_name, &["--help"]) {
45 Ok(_) => unreachable!(),
46 Err(exit) => exit.output,
47 };
48 Err(argh::EarlyExit {
49 output: format!("{help} -v, --version print version information and exit"),
50 status: Ok(()),
51 })
52 }
53 _ => T::from_args(command_name, args).map(|app| Self {
54 app,
55 _version_marker: PhantomData,
56 }),
57 }
58 }
59}