parkour/
util.rs

1//! Several utility types.
2
3use std::fmt;
4use std::fmt::Write as _;
5
6use crate::actions::ApplyResult;
7use crate::Parse;
8
9/// The parsing context for a flag.
10///
11/// A flag is either short (i.e. it starts with a single dash) or long (i.e. it
12/// starts with two dashes). Note that the dashes should **not** be written in
13/// the string, i.e. use `Flag::Long("version")`, not `Flag::Long("--version")`.
14///
15/// Arguments can often be specified with a long and a short flag (e.g. `--help`
16/// and `-h`); Use `Flag::LongShort("help", "h")` in this case. If an argument
17/// has more than 2 flags, use `Flag::Many(vec![...])`.
18#[derive(Debug, Clone)]
19pub enum Flag<'a> {
20    /// A short flag, like `-h`
21    Short(&'a str),
22    /// A long flag, like `--help`
23    Long(&'a str),
24    /// A flag with a long and a short alias, e.g. `-h,--help`.
25    LongShort(&'a str, &'a str),
26    /// A flag with multiple aliases
27    Many(Box<[Flag<'a>]>),
28}
29
30impl Flag<'_> {
31    /// Returns the first alias of the flag as a [String].
32    pub fn first_to_string(&self) -> String {
33        match self {
34            &Flag::Short(s) => format!("-{}", s),
35            &Flag::Long(l) => format!("--{}", l),
36            &Flag::LongShort(l, _) => format!("--{}", l),
37            Flag::Many(v) => v[0].first_to_string(),
38        }
39    }
40
41    /// Parses a flag from a [`Parse`] instance.
42    pub fn from_input<'a, P: Parse>(input: &mut P, context: &Flag<'a>) -> ApplyResult {
43        Ok(match context {
44            Flag::Short(f) => input.parse_short_flag(f),
45            Flag::Long(f) => input.parse_long_flag(f),
46            Flag::LongShort(l, s) => {
47                input.parse_long_flag(l) || input.parse_short_flag(s)
48            }
49            Flag::Many(flags) => {
50                flags.iter().any(|flag| Self::from_input(input, flag).is_ok())
51            }
52        })
53    }
54}
55
56impl fmt::Display for Flag<'_> {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        match self {
59            Flag::Short(s) => write!(f, "-{}", s),
60            Flag::Long(l) => write!(f, "--{}", l),
61            Flag::LongShort(l, s) => write!(f, "--{},-{}", l, s),
62            Flag::Many(v) => {
63                for (i, flag) in v.iter().enumerate() {
64                    if i > 0 {
65                        f.write_char(',')?;
66                    }
67                    fmt::Display::fmt(flag, f)?;
68                }
69                Ok(())
70            }
71        }
72    }
73}
74
75/// The parsing context for a named argument, e.g. `--help=config`.
76#[derive(Debug, Clone)]
77pub struct ArgCtx<'a, C> {
78    /// The flag before the argument value(s)
79    pub flag: Flag<'a>,
80    /// The context for the argument value(s)
81    pub inner: C,
82}
83
84impl<'a, C> ArgCtx<'a, C> {
85    /// Creates a new `ArgCtx` instance
86    pub fn new(flag: Flag<'a>, inner: C) -> Self {
87        Self { flag, inner }
88    }
89}
90
91impl<'a, C: Default> From<Flag<'a>> for ArgCtx<'a, C> {
92    fn from(flag: Flag<'a>) -> Self {
93        ArgCtx { flag, inner: C::default() }
94    }
95}
96
97/// The parsing context for a positional argument.
98#[derive(Debug, Clone)]
99pub struct PosCtx<'a, C> {
100    /// The name of the positional argument, used in error messages
101    pub name: &'a str,
102    /// The context for the argument value
103    pub inner: C,
104}
105
106impl<'a, C> PosCtx<'a, C> {
107    /// Creates a new `PosCtx` instance
108    pub fn new(name: &'a str, inner: C) -> Self {
109        Self { name, inner }
110    }
111}
112
113impl<'a, C: Default> From<&'a str> for PosCtx<'a, C> {
114    fn from(name: &'a str) -> Self {
115        PosCtx { name, inner: C::default() }
116    }
117}