1use std::{
3 ffi::{OsStr, OsString},
4 fmt::{Display, Formatter, Result},
5 mem,
6 rc::Rc,
7 result::Result as StdResult,
8};
9
10use crate::{
12 args::{AnyArg, Arg, ArgSettings, Base, DispOrder, Switched, Valued},
13 map::{self, VecMap},
14 INTERNAL_ERROR_MSG,
15};
16
17#[allow(missing_debug_implementations)]
18#[doc(hidden)]
19#[derive(Default, Clone)]
20pub struct OptBuilder<'n, 'e>
21where
22 'n: 'e,
23{
24 pub b: Base<'n, 'e>,
25 pub s: Switched<'e>,
26 pub v: Valued<'n, 'e>,
27}
28
29impl<'n, 'e> OptBuilder<'n, 'e> {
30 pub fn new(name: &'n str) -> Self {
31 OptBuilder {
32 b: Base::new(name),
33 ..Default::default()
34 }
35 }
36}
37
38impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for OptBuilder<'n, 'e> {
39 fn from(a: &'z Arg<'n, 'e>) -> Self {
40 OptBuilder {
41 b: Base::from(a),
42 s: Switched::from(a),
43 v: Valued::from(a),
44 }
45 }
46}
47
48impl<'n, 'e> From<Arg<'n, 'e>> for OptBuilder<'n, 'e> {
49 fn from(mut a: Arg<'n, 'e>) -> Self {
50 a.v.fill_in();
51 OptBuilder {
52 b: mem::take(&mut a.b),
53 s: mem::take(&mut a.s),
54 v: mem::take(&mut a.v),
55 }
56 }
57}
58
59impl<'n, 'e> Display for OptBuilder<'n, 'e> {
60 fn fmt(&self, f: &mut Formatter) -> Result {
61 debugln!("OptBuilder::fmt:{}", self.b.name);
62 let sep = if self.b.is_set(ArgSettings::RequireEquals) {
63 "="
64 } else {
65 " "
66 };
67 if let Some(l) = self.s.long {
69 write!(f, "--{}{}", l, sep)?;
70 } else {
71 write!(f, "-{}{}", self.s.short.unwrap(), sep)?;
72 }
73 let delim = if self.is_set(ArgSettings::RequireDelimiter) {
74 self.v.val_delim.expect(INTERNAL_ERROR_MSG)
75 } else {
76 ' '
77 };
78
79 if let Some(ref vec) = self.v.val_names {
81 let mut it = vec.iter().peekable();
82 while let Some((_, val)) = it.next() {
83 write!(f, "<{}>", val)?;
84 if it.peek().is_some() {
85 write!(f, "{}", delim)?;
86 }
87 }
88 let num = vec.len();
89 if self.is_set(ArgSettings::Multiple) && num == 1 {
90 write!(f, "...")?;
91 }
92 } else if let Some(num) = self.v.num_vals {
93 let mut it = (0..num).peekable();
94 while let Some(_) = it.next() {
95 write!(f, "<{}>", self.b.name)?;
96 if it.peek().is_some() {
97 write!(f, "{}", delim)?;
98 }
99 }
100 if self.is_set(ArgSettings::Multiple) && num == 1 {
101 write!(f, "...")?;
102 }
103 } else {
104 write!(
105 f,
106 "<{}>{}",
107 self.b.name,
108 if self.is_set(ArgSettings::Multiple) {
109 "..."
110 } else {
111 ""
112 }
113 )?;
114 }
115
116 Ok(())
117 }
118}
119
120impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> {
121 fn name(&self) -> &'n str {
122 self.b.name
123 }
124 fn overrides(&self) -> Option<&[&'e str]> {
125 self.b.overrides.as_ref().map(|o| &o[..])
126 }
127 fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> {
128 self.b.requires.as_ref().map(|o| &o[..])
129 }
130 fn blacklist(&self) -> Option<&[&'e str]> {
131 self.b.blacklist.as_ref().map(|o| &o[..])
132 }
133 fn required_unless(&self) -> Option<&[&'e str]> {
134 self.b.r_unless.as_ref().map(|o| &o[..])
135 }
136 fn val_names(&self) -> Option<&VecMap<&'e str>> {
137 self.v.val_names.as_ref()
138 }
139 fn is_set(&self, s: ArgSettings) -> bool {
140 self.b.settings.is_set(s)
141 }
142 fn has_switch(&self) -> bool {
143 true
144 }
145 fn set(&mut self, s: ArgSettings) {
146 self.b.settings.set(s)
147 }
148 fn max_vals(&self) -> Option<u64> {
149 self.v.max_vals
150 }
151 fn val_terminator(&self) -> Option<&'e str> {
152 self.v.terminator
153 }
154 fn num_vals(&self) -> Option<u64> {
155 self.v.num_vals
156 }
157 fn possible_vals(&self) -> Option<&[&'e str]> {
158 self.v.possible_vals.as_ref().map(|o| &o[..])
159 }
160 #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))]
161 fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
162 self.v.validator.as_ref()
163 }
164 #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))]
165 fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> {
166 self.v.validator_os.as_ref()
167 }
168 fn min_vals(&self) -> Option<u64> {
169 self.v.min_vals
170 }
171 fn short(&self) -> Option<char> {
172 self.s.short
173 }
174 fn long(&self) -> Option<&'e str> {
175 self.s.long
176 }
177 fn val_delim(&self) -> Option<char> {
178 self.v.val_delim
179 }
180 fn takes_value(&self) -> bool {
181 true
182 }
183 fn help(&self) -> Option<&'e str> {
184 self.b.help
185 }
186 fn long_help(&self) -> Option<&'e str> {
187 self.b.long_help
188 }
189 fn default_val(&self) -> Option<&'e OsStr> {
190 self.v.default_val
191 }
192 fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
193 self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
194 }
195 fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> {
196 self.v
197 .env
198 .as_ref()
199 .map(|&(key, ref value)| (key, value.as_ref()))
200 }
201 fn longest_filter(&self) -> bool {
202 true
203 }
204 fn aliases(&self) -> Option<Vec<&'e str>> {
205 if let Some(ref aliases) = self.s.aliases {
206 let vis_aliases: Vec<_> = aliases
207 .iter()
208 .filter_map(|&(n, v)| if v { Some(n) } else { None })
209 .collect();
210 if vis_aliases.is_empty() {
211 None
212 } else {
213 Some(vis_aliases)
214 }
215 } else {
216 None
217 }
218 }
219}
220
221impl<'n, 'e> DispOrder for OptBuilder<'n, 'e> {
222 fn disp_ord(&self) -> usize {
223 self.s.disp_ord
224 }
225}
226
227impl<'n, 'e> PartialEq for OptBuilder<'n, 'e> {
228 fn eq(&self, other: &OptBuilder<'n, 'e>) -> bool {
229 self.b == other.b
230 }
231}
232
233#[cfg(test)]
234mod test {
235 use super::OptBuilder;
236 use crate::{args::settings::ArgSettings, map::VecMap};
237
238 #[test]
239 fn optbuilder_display1() {
240 let mut o = OptBuilder::new("opt");
241 o.s.long = Some("option");
242 o.b.settings.set(ArgSettings::Multiple);
243
244 assert_eq!(&*format!("{}", o), "--option <opt>...");
245 }
246
247 #[test]
248 fn optbuilder_display2() {
249 let mut v_names = VecMap::new();
250 v_names.insert(0, "file");
251 v_names.insert(1, "name");
252
253 let mut o2 = OptBuilder::new("opt");
254 o2.s.short = Some('o');
255 o2.v.val_names = Some(v_names);
256
257 assert_eq!(&*format!("{}", o2), "-o <file> <name>");
258 }
259
260 #[test]
261 fn optbuilder_display3() {
262 let mut v_names = VecMap::new();
263 v_names.insert(0, "file");
264 v_names.insert(1, "name");
265
266 let mut o2 = OptBuilder::new("opt");
267 o2.s.short = Some('o');
268 o2.v.val_names = Some(v_names);
269 o2.b.settings.set(ArgSettings::Multiple);
270
271 assert_eq!(&*format!("{}", o2), "-o <file> <name>");
272 }
273
274 #[test]
275 fn optbuilder_display_single_alias() {
276 let mut o = OptBuilder::new("opt");
277 o.s.long = Some("option");
278 o.s.aliases = Some(vec![("als", true)]);
279
280 assert_eq!(&*format!("{}", o), "--option <opt>");
281 }
282
283 #[test]
284 fn optbuilder_display_multiple_aliases() {
285 let mut o = OptBuilder::new("opt");
286 o.s.long = Some("option");
287 o.s.aliases = Some(vec![
288 ("als_not_visible", false),
289 ("als2", true),
290 ("als3", true),
291 ("als4", true),
292 ]);
293 assert_eq!(&*format!("{}", o), "--option <opt>");
294 }
295}