1 // Std
2 use std::{ops::BitOr, str::FromStr};
3 
4 // Third party
5 use bitflags::bitflags;
6 
7 bitflags! {
8     struct Flags: u32 {
9         const REQUIRED         = 1;
10         const MULTIPLE_OCC     = 1 << 1;
11         const NO_EMPTY_VALS    = 1 << 2;
12         const GLOBAL           = 1 << 3;
13         const HIDDEN           = 1 << 4;
14         const TAKES_VAL        = 1 << 5;
15         const USE_DELIM        = 1 << 6;
16         const NEXT_LINE_HELP   = 1 << 7;
17         const R_UNLESS_ALL     = 1 << 8;
18         const REQ_DELIM        = 1 << 9;
19         const DELIM_NOT_SET    = 1 << 10;
20         const HIDE_POS_VALS    = 1 << 11;
21         const ALLOW_TAC_VALS   = 1 << 12;
22         const REQUIRE_EQUALS   = 1 << 13;
23         const LAST             = 1 << 14;
24         const HIDE_DEFAULT_VAL = 1 << 15;
25         const CASE_INSENSITIVE = 1 << 16;
26         #[cfg(feature = "env")]
27         const HIDE_ENV_VALS    = 1 << 17;
28         const HIDDEN_SHORT_H   = 1 << 18;
29         const HIDDEN_LONG_H    = 1 << 19;
30         const MULTIPLE_VALS    = 1 << 20;
31         #[cfg(feature = "env")]
32         const HIDE_ENV         = 1 << 21;
33         const UTF8_NONE        = 1 << 22;
34     }
35 }
36 
37 #[doc(hidden)]
38 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
39 pub struct ArgFlags(Flags);
40 
41 impl Default for ArgFlags {
default() -> Self42     fn default() -> Self {
43         Self::empty()
44     }
45 }
46 
47 // @TODO @p6 @internal: Reorder alphabetically
48 impl_settings! { ArgSettings, ArgFlags,
49     Required("required") => Flags::REQUIRED,
50     MultipleOccurrences("multipleoccurrences") => Flags::MULTIPLE_OCC,
51     MultipleValues("multiplevalues") => Flags::MULTIPLE_VALS,
52     ForbidEmptyValues("forbidemptyvalues") => Flags::NO_EMPTY_VALS,
53     Hidden("hidden") => Flags::HIDDEN,
54     TakesValue("takesvalue") => Flags::TAKES_VAL,
55     UseValueDelimiter("usevaluedelimiter") => Flags::USE_DELIM,
56     NextLineHelp("nextlinehelp") => Flags::NEXT_LINE_HELP,
57     RequiredUnlessAll("requiredunlessall") => Flags::R_UNLESS_ALL,
58     RequireDelimiter("requiredelimiter") => Flags::REQ_DELIM,
59     HidePossibleValues("hidepossiblevalues") => Flags::HIDE_POS_VALS,
60     AllowHyphenValues("allowhyphenvalues") => Flags::ALLOW_TAC_VALS,
61     RequireEquals("requireequals") => Flags::REQUIRE_EQUALS,
62     Last("last") => Flags::LAST,
63     IgnoreCase("ignorecase") => Flags::CASE_INSENSITIVE,
64     #[cfg(feature = "env")]
65     HideEnv("hideenv") => Flags::HIDE_ENV,
66     #[cfg(feature = "env")]
67     HideEnvValues("hideenvvalues") => Flags::HIDE_ENV_VALS,
68     HideDefaultValue("hidedefaultvalue") => Flags::HIDE_DEFAULT_VAL,
69     HiddenShortHelp("hiddenshorthelp") => Flags::HIDDEN_SHORT_H,
70     HiddenLongHelp("hiddenlonghelp") => Flags::HIDDEN_LONG_H,
71     AllowInvalidUtf8("allowinvalidutf8") => Flags::UTF8_NONE
72 }
73 
74 /// Various settings that apply to arguments and may be set, unset, and checked via getter/setter
75 /// methods [`Arg::setting`], [`Arg::unset_setting`], and [`Arg::is_set`]. This is what the
76 /// [`Arg`] methods which accept a `bool` use internally.
77 ///
78 /// [`Arg`]: crate::Arg
79 /// [`Arg::setting`]: crate::Arg::setting()
80 /// [`Arg::unset_setting`]: crate::Arg::unset_setting()
81 /// [`Arg::is_set`]: crate::Arg::is_set()
82 #[derive(Debug, PartialEq, Copy, Clone)]
83 pub enum ArgSettings {
84     /// Specifies that an arg must be used
85     Required,
86     /// Allows an arg to accept multiple values
87     MultipleValues,
88     /// Allows an arg to appear multiple times
89     MultipleOccurrences,
90     /// Forbids an arg from accepting empty values such as `""`
91     ForbidEmptyValues,
92     /// Hides an arg from the help message
93     Hidden,
94     /// Allows an argument to take a value (such as `--option value`)
95     TakesValue,
96     /// Enables a delimiter to break up arguments `--option val1,val2,val3` becomes three values
97     /// (`val1`, `val2`, and `val3`) instead of the default one (`val1,val2,val3`)
98     UseValueDelimiter,
99     /// Tells an arg to display it's help on the line below the arg itself in the help message
100     NextLineHelp,
101     /// Says that arg *must* use a delimiter to separate values
102     RequireDelimiter,
103     /// Hides the possible values from the help message
104     HidePossibleValues,
105     /// Allows values that start with a hyphen
106     AllowHyphenValues,
107     /// Requires that an equals be used to provide a value to an option such as `--option=value`
108     RequireEquals,
109     /// Says that a positional arg will be the last positional, and requires `--` to be accessed.
110     /// It can also be accessed early (i.e. before other positionals) by providing `--`
111     Last,
112     /// Hides the default value from the help message
113     HideDefaultValue,
114     /// Possible values become case insensitive
115     IgnoreCase,
116     /// Hides environment variable arguments from the help message
117     #[cfg(feature = "env")]
118     HideEnv,
119     /// Hides any values currently assigned to ENV variables in the help message (good for sensitive
120     /// information)
121     #[cfg(feature = "env")]
122     HideEnvValues,
123     /// The argument should **not** be shown in short help text
124     HiddenShortHelp,
125     /// The argument should **not** be shown in long help text
126     HiddenLongHelp,
127     /// Specifies that option values that are invalid UTF-8 should *not* be treated as an error.
128     AllowInvalidUtf8,
129 
130     #[doc(hidden)]
131     RequiredUnlessAll,
132 }
133 
134 #[cfg(test)]
135 mod test {
136     use super::ArgSettings;
137 
138     #[test]
arg_settings_fromstr()139     fn arg_settings_fromstr() {
140         assert_eq!(
141             "allowhyphenvalues".parse::<ArgSettings>().unwrap(),
142             ArgSettings::AllowHyphenValues
143         );
144         assert_eq!(
145             "forbidemptyvalues".parse::<ArgSettings>().unwrap(),
146             ArgSettings::ForbidEmptyValues
147         );
148         assert_eq!(
149             "hidepossiblevalues".parse::<ArgSettings>().unwrap(),
150             ArgSettings::HidePossibleValues
151         );
152         assert_eq!(
153             "hidden".parse::<ArgSettings>().unwrap(),
154             ArgSettings::Hidden
155         );
156         assert_eq!(
157             "nextlinehelp".parse::<ArgSettings>().unwrap(),
158             ArgSettings::NextLineHelp
159         );
160         assert_eq!(
161             "requiredunlessall".parse::<ArgSettings>().unwrap(),
162             ArgSettings::RequiredUnlessAll
163         );
164         assert_eq!(
165             "requiredelimiter".parse::<ArgSettings>().unwrap(),
166             ArgSettings::RequireDelimiter
167         );
168         assert_eq!(
169             "required".parse::<ArgSettings>().unwrap(),
170             ArgSettings::Required
171         );
172         assert_eq!(
173             "takesvalue".parse::<ArgSettings>().unwrap(),
174             ArgSettings::TakesValue
175         );
176         assert_eq!(
177             "usevaluedelimiter".parse::<ArgSettings>().unwrap(),
178             ArgSettings::UseValueDelimiter
179         );
180         assert_eq!(
181             "requireequals".parse::<ArgSettings>().unwrap(),
182             ArgSettings::RequireEquals
183         );
184         assert_eq!("last".parse::<ArgSettings>().unwrap(), ArgSettings::Last);
185         assert_eq!(
186             "hidedefaultvalue".parse::<ArgSettings>().unwrap(),
187             ArgSettings::HideDefaultValue
188         );
189         assert_eq!(
190             "ignorecase".parse::<ArgSettings>().unwrap(),
191             ArgSettings::IgnoreCase
192         );
193         #[cfg(feature = "env")]
194         assert_eq!(
195             "hideenv".parse::<ArgSettings>().unwrap(),
196             ArgSettings::HideEnv
197         );
198         #[cfg(feature = "env")]
199         assert_eq!(
200             "hideenvvalues".parse::<ArgSettings>().unwrap(),
201             ArgSettings::HideEnvValues
202         );
203         assert_eq!(
204             "hiddenshorthelp".parse::<ArgSettings>().unwrap(),
205             ArgSettings::HiddenShortHelp
206         );
207         assert_eq!(
208             "hiddenlonghelp".parse::<ArgSettings>().unwrap(),
209             ArgSettings::HiddenLongHelp
210         );
211         assert_eq!(
212             "allowinvalidutf8".parse::<ArgSettings>().unwrap(),
213             ArgSettings::AllowInvalidUtf8
214         );
215         assert!("hahahaha".parse::<ArgSettings>().is_err());
216     }
217 }
218