1 // Internal 2 use crate::builder::IntoResettable; 3 use crate::util::Id; 4 5 /// Family of related [arguments]. 6 /// 7 /// By placing arguments in a logical group, you can create easier requirement and 8 /// exclusion rules instead of having to list each argument individually, or when you want a rule 9 /// to apply "any but not all" arguments. 10 /// 11 /// For instance, you can make an entire `ArgGroup` required. If [`ArgGroup::multiple(true)`] is 12 /// set, this means that at least one argument from that group must be present. If 13 /// [`ArgGroup::multiple(false)`] is set (the default), one and *only* one must be present. 14 /// 15 /// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for 16 /// another argument, meaning any of the arguments that belong to that group will cause a failure 17 /// if present, or must be present respectively. 18 /// 19 /// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be 20 /// present out of a given set. Imagine that you had multiple arguments, and you want one of them 21 /// to be required, but making all of them required isn't feasible because perhaps they conflict 22 /// with each other. For example, lets say that you were building an application where one could 23 /// set a given version number by supplying a string with an option argument, i.e. 24 /// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number 25 /// and simply incrementing one of the three numbers. So you create three flags `--major`, 26 /// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to 27 /// specify that *at least one* of them is used. For this, you can create a group. 28 /// 29 /// Finally, you may use `ArgGroup`s to pull a value from a group of arguments when you don't care 30 /// exactly which argument was actually used at runtime. 31 /// 32 /// # Examples 33 /// 34 /// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of 35 /// the arguments from the specified group is present at runtime. 36 /// 37 /// ```rust 38 /// # use clap_builder as clap; 39 /// # use clap::{Command, arg, ArgGroup, error::ErrorKind}; 40 /// let result = Command::new("cmd") 41 /// .arg(arg!(--"set-ver" <ver> "set the version manually")) 42 /// .arg(arg!(--major "auto increase major")) 43 /// .arg(arg!(--minor "auto increase minor")) 44 /// .arg(arg!(--patch "auto increase patch")) 45 /// .group(ArgGroup::new("vers") 46 /// .args(["set-ver", "major", "minor", "patch"]) 47 /// .required(true)) 48 /// .try_get_matches_from(vec!["cmd", "--major", "--patch"]); 49 /// // Because we used two args in the group it's an error 50 /// assert!(result.is_err()); 51 /// let err = result.unwrap_err(); 52 /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); 53 /// ``` 54 /// 55 /// This next example shows a passing parse of the same scenario 56 /// ```rust 57 /// # use clap_builder as clap; 58 /// # use clap::{Command, arg, ArgGroup, Id}; 59 /// let result = Command::new("cmd") 60 /// .arg(arg!(--"set-ver" <ver> "set the version manually")) 61 /// .arg(arg!(--major "auto increase major")) 62 /// .arg(arg!(--minor "auto increase minor")) 63 /// .arg(arg!(--patch "auto increase patch")) 64 /// .group(ArgGroup::new("vers") 65 /// .args(["set-ver", "major", "minor","patch"]) 66 /// .required(true)) 67 /// .try_get_matches_from(vec!["cmd", "--major"]); 68 /// assert!(result.is_ok()); 69 /// let matches = result.unwrap(); 70 /// // We may not know which of the args was used, so we can test for the group... 71 /// assert!(matches.contains_id("vers")); 72 /// // We can also ask the group which arg was used 73 /// assert_eq!(matches 74 /// .get_one::<Id>("vers") 75 /// .expect("`vers` is required") 76 /// .as_str(), 77 /// "major" 78 /// ); 79 /// // we could also alternatively check each arg individually (not shown here) 80 /// ``` 81 /// [`ArgGroup::multiple(true)`]: ArgGroup::multiple() 82 /// 83 /// [`ArgGroup::multiple(false)`]: ArgGroup::multiple() 84 /// [arguments]: crate::Arg 85 /// [conflict]: crate::Arg::conflicts_with() 86 /// [requirement]: crate::Arg::requires() 87 #[derive(Default, Clone, Debug, PartialEq, Eq)] 88 pub struct ArgGroup { 89 pub(crate) id: Id, 90 pub(crate) args: Vec<Id>, 91 pub(crate) required: bool, 92 pub(crate) requires: Vec<Id>, 93 pub(crate) conflicts: Vec<Id>, 94 pub(crate) multiple: bool, 95 } 96 97 /// # Builder 98 impl ArgGroup { 99 /// Create a `ArgGroup` using a unique name. 100 /// 101 /// The name will be used to get values from the group or refer to the group inside of conflict 102 /// and requirement rules. 103 /// 104 /// # Examples 105 /// 106 /// ```rust 107 /// # use clap_builder as clap; 108 /// # use clap::{Command, ArgGroup}; 109 /// ArgGroup::new("config") 110 /// # ; 111 /// ``` new(id: impl Into<Id>) -> Self112 pub fn new(id: impl Into<Id>) -> Self { 113 ArgGroup::default().id(id) 114 } 115 116 /// Sets the group name. 117 /// 118 /// # Examples 119 /// 120 /// ```rust 121 /// # use clap_builder as clap; 122 /// # use clap::{Command, ArgGroup}; 123 /// ArgGroup::default().id("config") 124 /// # ; 125 /// ``` 126 #[must_use] id(mut self, id: impl Into<Id>) -> Self127 pub fn id(mut self, id: impl Into<Id>) -> Self { 128 self.id = id.into(); 129 self 130 } 131 132 /// Adds an [argument] to this group by name 133 /// 134 /// # Examples 135 /// 136 /// ```rust 137 /// # use clap_builder as clap; 138 /// # use clap::{Command, Arg, ArgGroup, ArgAction}; 139 /// let m = Command::new("myprog") 140 /// .arg(Arg::new("flag") 141 /// .short('f') 142 /// .action(ArgAction::SetTrue)) 143 /// .arg(Arg::new("color") 144 /// .short('c') 145 /// .action(ArgAction::SetTrue)) 146 /// .group(ArgGroup::new("req_flags") 147 /// .arg("flag") 148 /// .arg("color")) 149 /// .get_matches_from(vec!["myprog", "-f"]); 150 /// // maybe we don't know which of the two flags was used... 151 /// assert!(m.contains_id("req_flags")); 152 /// // but we can also check individually if needed 153 /// assert!(m.contains_id("flag")); 154 /// ``` 155 /// [argument]: crate::Arg 156 #[must_use] arg(mut self, arg_id: impl IntoResettable<Id>) -> Self157 pub fn arg(mut self, arg_id: impl IntoResettable<Id>) -> Self { 158 if let Some(arg_id) = arg_id.into_resettable().into_option() { 159 self.args.push(arg_id); 160 } else { 161 self.args.clear(); 162 } 163 self 164 } 165 166 /// Adds multiple [arguments] to this group by name 167 /// 168 /// # Examples 169 /// 170 /// ```rust 171 /// # use clap_builder as clap; 172 /// # use clap::{Command, Arg, ArgGroup, ArgAction}; 173 /// let m = Command::new("myprog") 174 /// .arg(Arg::new("flag") 175 /// .short('f') 176 /// .action(ArgAction::SetTrue)) 177 /// .arg(Arg::new("color") 178 /// .short('c') 179 /// .action(ArgAction::SetTrue)) 180 /// .group(ArgGroup::new("req_flags") 181 /// .args(["flag", "color"])) 182 /// .get_matches_from(vec!["myprog", "-f"]); 183 /// // maybe we don't know which of the two flags was used... 184 /// assert!(m.contains_id("req_flags")); 185 /// // but we can also check individually if needed 186 /// assert!(m.contains_id("flag")); 187 /// ``` 188 /// [arguments]: crate::Arg 189 #[must_use] args(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self190 pub fn args(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self { 191 for n in ns { 192 self = self.arg(n); 193 } 194 self 195 } 196 197 /// Getters for all args. It will return a vector of `Id` 198 /// 199 /// # Example 200 /// 201 /// ```rust 202 /// # use clap_builder as clap; 203 /// # use clap::{ArgGroup}; 204 /// let args: Vec<&str> = vec!["a1".into(), "a4".into()]; 205 /// let grp = ArgGroup::new("program").args(&args); 206 /// 207 /// for (pos, arg) in grp.get_args().enumerate() { 208 /// assert_eq!(*arg, args[pos]); 209 /// } 210 /// ``` get_args(&self) -> impl Iterator<Item = &Id>211 pub fn get_args(&self) -> impl Iterator<Item = &Id> { 212 self.args.iter() 213 } 214 215 /// Allows more than one of the [`Arg`]s in this group to be used. (Default: `false`) 216 /// 217 /// # Examples 218 /// 219 /// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the 220 /// group 221 /// 222 /// ```rust 223 /// # use clap_builder as clap; 224 /// # use clap::{Command, Arg, ArgGroup, ArgAction}; 225 /// let m = Command::new("myprog") 226 /// .arg(Arg::new("flag") 227 /// .short('f') 228 /// .action(ArgAction::SetTrue)) 229 /// .arg(Arg::new("color") 230 /// .short('c') 231 /// .action(ArgAction::SetTrue)) 232 /// .group(ArgGroup::new("req_flags") 233 /// .args(["flag", "color"]) 234 /// .multiple(true)) 235 /// .get_matches_from(vec!["myprog", "-f", "-c"]); 236 /// // maybe we don't know which of the two flags was used... 237 /// assert!(m.contains_id("req_flags")); 238 /// ``` 239 /// In this next example, we show the default behavior (i.e. `multiple(false)) which will throw 240 /// an error if more than one of the args in the group was used. 241 /// 242 /// ```rust 243 /// # use clap_builder as clap; 244 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 245 /// let result = Command::new("myprog") 246 /// .arg(Arg::new("flag") 247 /// .short('f') 248 /// .action(ArgAction::SetTrue)) 249 /// .arg(Arg::new("color") 250 /// .short('c') 251 /// .action(ArgAction::SetTrue)) 252 /// .group(ArgGroup::new("req_flags") 253 /// .args(["flag", "color"])) 254 /// .try_get_matches_from(vec!["myprog", "-f", "-c"]); 255 /// // Because we used both args in the group it's an error 256 /// assert!(result.is_err()); 257 /// let err = result.unwrap_err(); 258 /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); 259 /// ``` 260 /// 261 /// [`Arg`]: crate::Arg 262 #[inline] 263 #[must_use] multiple(mut self, yes: bool) -> Self264 pub fn multiple(mut self, yes: bool) -> Self { 265 self.multiple = yes; 266 self 267 } 268 269 /// Return true if the group allows more than one of the arguments 270 /// in this group to be used. (Default: `false`) 271 /// 272 /// # Example 273 /// 274 /// ```rust 275 /// # use clap_builder as clap; 276 /// # use clap::{ArgGroup}; 277 /// let mut group = ArgGroup::new("myprog") 278 /// .args(["f", "c"]) 279 /// .multiple(true); 280 /// 281 /// assert!(group.is_multiple()); 282 /// ``` is_multiple(&mut self) -> bool283 pub fn is_multiple(&mut self) -> bool { 284 self.multiple 285 } 286 287 /// Require an argument from the group to be present when parsing. 288 /// 289 /// This is unless conflicting with another argument. A required group will be displayed in 290 /// the usage string of the application in the format `<arg|arg2|arg3>`. 291 /// 292 /// **NOTE:** This setting only applies to the current [`Command`] / [`Subcommand`]s, and not 293 /// globally. 294 /// 295 /// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with 296 /// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group. 297 /// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which 298 /// states, '*At least* one arg from this group must be used. Using multiple is OK." 299 /// 300 /// # Examples 301 /// 302 /// ```rust 303 /// # use clap_builder as clap; 304 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 305 /// let result = Command::new("myprog") 306 /// .arg(Arg::new("flag") 307 /// .short('f') 308 /// .action(ArgAction::SetTrue)) 309 /// .arg(Arg::new("color") 310 /// .short('c') 311 /// .action(ArgAction::SetTrue)) 312 /// .group(ArgGroup::new("req_flags") 313 /// .args(["flag", "color"]) 314 /// .required(true)) 315 /// .try_get_matches_from(vec!["myprog"]); 316 /// // Because we didn't use any of the args in the group, it's an error 317 /// assert!(result.is_err()); 318 /// let err = result.unwrap_err(); 319 /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); 320 /// ``` 321 /// 322 /// [`Subcommand`]: crate::Subcommand 323 /// [`ArgGroup::multiple`]: ArgGroup::multiple() 324 /// [`Command`]: crate::Command 325 #[inline] 326 #[must_use] required(mut self, yes: bool) -> Self327 pub fn required(mut self, yes: bool) -> Self { 328 self.required = yes; 329 self 330 } 331 332 /// Specify an argument or group that must be present when this group is. 333 /// 334 /// This is not to be confused with a [required group]. Requirement rules function just like 335 /// [argument requirement rules], you can name other arguments or groups that must be present 336 /// when any one of the arguments from this group is used. 337 /// 338 /// **NOTE:** The name provided may be an argument or group name 339 /// 340 /// # Examples 341 /// 342 /// ```rust 343 /// # use clap_builder as clap; 344 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 345 /// let result = Command::new("myprog") 346 /// .arg(Arg::new("flag") 347 /// .short('f') 348 /// .action(ArgAction::SetTrue)) 349 /// .arg(Arg::new("color") 350 /// .short('c') 351 /// .action(ArgAction::SetTrue)) 352 /// .arg(Arg::new("debug") 353 /// .short('d') 354 /// .action(ArgAction::SetTrue)) 355 /// .group(ArgGroup::new("req_flags") 356 /// .args(["flag", "color"]) 357 /// .requires("debug")) 358 /// .try_get_matches_from(vec!["myprog", "-c"]); 359 /// // because we used an arg from the group, and the group requires "-d" to be used, it's an 360 /// // error 361 /// assert!(result.is_err()); 362 /// let err = result.unwrap_err(); 363 /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); 364 /// ``` 365 /// [required group]: ArgGroup::required() 366 /// [argument requirement rules]: crate::Arg::requires() 367 #[must_use] requires(mut self, id: impl IntoResettable<Id>) -> Self368 pub fn requires(mut self, id: impl IntoResettable<Id>) -> Self { 369 if let Some(id) = id.into_resettable().into_option() { 370 self.requires.push(id); 371 } else { 372 self.requires.clear(); 373 } 374 self 375 } 376 377 /// Specify arguments or groups that must be present when this group is. 378 /// 379 /// This is not to be confused with a [required group]. Requirement rules function just like 380 /// [argument requirement rules], you can name other arguments or groups that must be present 381 /// when one of the arguments from this group is used. 382 /// 383 /// **NOTE:** The names provided may be an argument or group name 384 /// 385 /// # Examples 386 /// 387 /// ```rust 388 /// # use clap_builder as clap; 389 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 390 /// let result = Command::new("myprog") 391 /// .arg(Arg::new("flag") 392 /// .short('f') 393 /// .action(ArgAction::SetTrue)) 394 /// .arg(Arg::new("color") 395 /// .short('c') 396 /// .action(ArgAction::SetTrue)) 397 /// .arg(Arg::new("debug") 398 /// .short('d') 399 /// .action(ArgAction::SetTrue)) 400 /// .arg(Arg::new("verb") 401 /// .short('v') 402 /// .action(ArgAction::SetTrue)) 403 /// .group(ArgGroup::new("req_flags") 404 /// .args(["flag", "color"]) 405 /// .requires_all(["debug", "verb"])) 406 /// .try_get_matches_from(vec!["myprog", "-c", "-d"]); 407 /// // because we used an arg from the group, and the group requires "-d" and "-v" to be used, 408 /// // yet we only used "-d" it's an error 409 /// assert!(result.is_err()); 410 /// let err = result.unwrap_err(); 411 /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); 412 /// ``` 413 /// [required group]: ArgGroup::required() 414 /// [argument requirement rules]: crate::Arg::requires_ifs() 415 #[must_use] requires_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self416 pub fn requires_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self { 417 for n in ns { 418 self = self.requires(n); 419 } 420 self 421 } 422 423 /// Specify an argument or group that must **not** be present when this group is. 424 /// 425 /// Exclusion (aka conflict) rules function just like [argument exclusion rules], you can name 426 /// other arguments or groups that must *not* be present when one of the arguments from this 427 /// group are used. 428 /// 429 /// **NOTE:** The name provided may be an argument, or group name 430 /// 431 /// # Examples 432 /// 433 /// ```rust 434 /// # use clap_builder as clap; 435 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 436 /// let result = Command::new("myprog") 437 /// .arg(Arg::new("flag") 438 /// .short('f') 439 /// .action(ArgAction::SetTrue)) 440 /// .arg(Arg::new("color") 441 /// .short('c') 442 /// .action(ArgAction::SetTrue)) 443 /// .arg(Arg::new("debug") 444 /// .short('d') 445 /// .action(ArgAction::SetTrue)) 446 /// .group(ArgGroup::new("req_flags") 447 /// .args(["flag", "color"]) 448 /// .conflicts_with("debug")) 449 /// .try_get_matches_from(vec!["myprog", "-c", "-d"]); 450 /// // because we used an arg from the group, and the group conflicts with "-d", it's an error 451 /// assert!(result.is_err()); 452 /// let err = result.unwrap_err(); 453 /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); 454 /// ``` 455 /// [argument exclusion rules]: crate::Arg::conflicts_with() 456 #[must_use] conflicts_with(mut self, id: impl IntoResettable<Id>) -> Self457 pub fn conflicts_with(mut self, id: impl IntoResettable<Id>) -> Self { 458 if let Some(id) = id.into_resettable().into_option() { 459 self.conflicts.push(id); 460 } else { 461 self.conflicts.clear(); 462 } 463 self 464 } 465 466 /// Specify arguments or groups that must **not** be present when this group is. 467 /// 468 /// Exclusion rules function just like [argument exclusion rules], you can name other arguments 469 /// or groups that must *not* be present when one of the arguments from this group are used. 470 /// 471 /// **NOTE:** The names provided may be an argument, or group name 472 /// 473 /// # Examples 474 /// 475 /// ```rust 476 /// # use clap_builder as clap; 477 /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 478 /// let result = Command::new("myprog") 479 /// .arg(Arg::new("flag") 480 /// .short('f') 481 /// .action(ArgAction::SetTrue)) 482 /// .arg(Arg::new("color") 483 /// .short('c') 484 /// .action(ArgAction::SetTrue)) 485 /// .arg(Arg::new("debug") 486 /// .short('d') 487 /// .action(ArgAction::SetTrue)) 488 /// .arg(Arg::new("verb") 489 /// .short('v') 490 /// .action(ArgAction::SetTrue)) 491 /// .group(ArgGroup::new("req_flags") 492 /// .args(["flag", "color"]) 493 /// .conflicts_with_all(["debug", "verb"])) 494 /// .try_get_matches_from(vec!["myprog", "-c", "-v"]); 495 /// // because we used an arg from the group, and the group conflicts with either "-v" or "-d" 496 /// // it's an error 497 /// assert!(result.is_err()); 498 /// let err = result.unwrap_err(); 499 /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); 500 /// ``` 501 /// 502 /// [argument exclusion rules]: crate::Arg::conflicts_with_all() 503 #[must_use] conflicts_with_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self504 pub fn conflicts_with_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self { 505 for n in ns { 506 self = self.conflicts_with(n); 507 } 508 self 509 } 510 } 511 512 /// # Reflection 513 impl ArgGroup { 514 /// Get the name of the group 515 #[inline] get_id(&self) -> &Id516 pub fn get_id(&self) -> &Id { 517 &self.id 518 } 519 520 /// Reports whether [`ArgGroup::required`] is set 521 #[inline] is_required_set(&self) -> bool522 pub fn is_required_set(&self) -> bool { 523 self.required 524 } 525 } 526 527 impl From<&'_ ArgGroup> for ArgGroup { from(g: &ArgGroup) -> Self528 fn from(g: &ArgGroup) -> Self { 529 g.clone() 530 } 531 } 532 533 #[cfg(test)] 534 mod test { 535 use super::*; 536 537 #[test] groups()538 fn groups() { 539 let g = ArgGroup::new("test") 540 .arg("a1") 541 .arg("a4") 542 .args(["a2", "a3"]) 543 .required(true) 544 .conflicts_with("c1") 545 .conflicts_with_all(["c2", "c3"]) 546 .conflicts_with("c4") 547 .requires("r1") 548 .requires_all(["r2", "r3"]) 549 .requires("r4"); 550 551 let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()]; 552 let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()]; 553 let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()]; 554 555 assert_eq!(g.args, args); 556 assert_eq!(g.requires, reqs); 557 assert_eq!(g.conflicts, confs); 558 } 559 560 #[test] test_from()561 fn test_from() { 562 let g = ArgGroup::new("test") 563 .arg("a1") 564 .arg("a4") 565 .args(["a2", "a3"]) 566 .required(true) 567 .conflicts_with("c1") 568 .conflicts_with_all(["c2", "c3"]) 569 .conflicts_with("c4") 570 .requires("r1") 571 .requires_all(["r2", "r3"]) 572 .requires("r4"); 573 574 let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()]; 575 let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()]; 576 let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()]; 577 578 let g2 = ArgGroup::from(&g); 579 assert_eq!(g2.args, args); 580 assert_eq!(g2.requires, reqs); 581 assert_eq!(g2.conflicts, confs); 582 } 583 584 // This test will *fail to compile* if ArgGroup is not Send + Sync 585 #[test] arg_group_send_sync()586 fn arg_group_send_sync() { 587 fn foo<T: Send + Sync>(_: T) {} 588 foo(ArgGroup::new("test")) 589 } 590 591 #[test] arg_group_expose_is_multiple_helper()592 fn arg_group_expose_is_multiple_helper() { 593 let args: Vec<Id> = vec!["a1".into(), "a4".into()]; 594 595 let mut grp_multiple = ArgGroup::new("test_multiple").args(&args).multiple(true); 596 assert!(grp_multiple.is_multiple()); 597 598 let mut grp_not_multiple = ArgGroup::new("test_multiple").args(&args).multiple(false); 599 assert!(!grp_not_multiple.is_multiple()); 600 } 601 602 #[test] arg_group_expose_get_args_helper()603 fn arg_group_expose_get_args_helper() { 604 let args: Vec<Id> = vec!["a1".into(), "a4".into()]; 605 let grp = ArgGroup::new("program").args(&args); 606 607 for (pos, arg) in grp.get_args().enumerate() { 608 assert_eq!(*arg, args[pos]); 609 } 610 } 611 } 612