119625d8cSopenharmony_ci// Internal
219625d8cSopenharmony_ciuse crate::builder::IntoResettable;
319625d8cSopenharmony_ciuse crate::util::Id;
419625d8cSopenharmony_ci
519625d8cSopenharmony_ci/// Family of related [arguments].
619625d8cSopenharmony_ci///
719625d8cSopenharmony_ci/// By placing arguments in a logical group, you can create easier requirement and
819625d8cSopenharmony_ci/// exclusion rules instead of having to list each argument individually, or when you want a rule
919625d8cSopenharmony_ci/// to apply "any but not all" arguments.
1019625d8cSopenharmony_ci///
1119625d8cSopenharmony_ci/// For instance, you can make an entire `ArgGroup` required. If [`ArgGroup::multiple(true)`] is
1219625d8cSopenharmony_ci/// set, this means that at least one argument from that group must be present. If
1319625d8cSopenharmony_ci/// [`ArgGroup::multiple(false)`] is set (the default), one and *only* one must be present.
1419625d8cSopenharmony_ci///
1519625d8cSopenharmony_ci/// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for
1619625d8cSopenharmony_ci/// another argument, meaning any of the arguments that belong to that group will cause a failure
1719625d8cSopenharmony_ci/// if present, or must be present respectively.
1819625d8cSopenharmony_ci///
1919625d8cSopenharmony_ci/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
2019625d8cSopenharmony_ci/// present out of a given set. Imagine that you had multiple arguments, and you want one of them
2119625d8cSopenharmony_ci/// to be required, but making all of them required isn't feasible because perhaps they conflict
2219625d8cSopenharmony_ci/// with each other. For example, lets say that you were building an application where one could
2319625d8cSopenharmony_ci/// set a given version number by supplying a string with an option argument, i.e.
2419625d8cSopenharmony_ci/// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number
2519625d8cSopenharmony_ci/// and simply incrementing one of the three numbers. So you create three flags `--major`,
2619625d8cSopenharmony_ci/// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to
2719625d8cSopenharmony_ci/// specify that *at least one* of them is used. For this, you can create a group.
2819625d8cSopenharmony_ci///
2919625d8cSopenharmony_ci/// Finally, you may use `ArgGroup`s to pull a value from a group of arguments when you don't care
3019625d8cSopenharmony_ci/// exactly which argument was actually used at runtime.
3119625d8cSopenharmony_ci///
3219625d8cSopenharmony_ci/// # Examples
3319625d8cSopenharmony_ci///
3419625d8cSopenharmony_ci/// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of
3519625d8cSopenharmony_ci/// the arguments from the specified group is present at runtime.
3619625d8cSopenharmony_ci///
3719625d8cSopenharmony_ci/// ```rust
3819625d8cSopenharmony_ci/// # use clap::{Command, arg, ArgGroup, error::ErrorKind};
3919625d8cSopenharmony_ci/// let result = Command::new("cmd")
4019625d8cSopenharmony_ci///     .arg(arg!(--"set-ver" <ver> "set the version manually"))
4119625d8cSopenharmony_ci///     .arg(arg!(--major           "auto increase major"))
4219625d8cSopenharmony_ci///     .arg(arg!(--minor           "auto increase minor"))
4319625d8cSopenharmony_ci///     .arg(arg!(--patch           "auto increase patch"))
4419625d8cSopenharmony_ci///     .group(ArgGroup::new("vers")
4519625d8cSopenharmony_ci///          .args(["set-ver", "major", "minor", "patch"])
4619625d8cSopenharmony_ci///          .required(true))
4719625d8cSopenharmony_ci///     .try_get_matches_from(vec!["cmd", "--major", "--patch"]);
4819625d8cSopenharmony_ci/// // Because we used two args in the group it's an error
4919625d8cSopenharmony_ci/// assert!(result.is_err());
5019625d8cSopenharmony_ci/// let err = result.unwrap_err();
5119625d8cSopenharmony_ci/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
5219625d8cSopenharmony_ci/// ```
5319625d8cSopenharmony_ci///
5419625d8cSopenharmony_ci/// This next example shows a passing parse of the same scenario
5519625d8cSopenharmony_ci/// ```rust
5619625d8cSopenharmony_ci/// # use clap::{Command, arg, ArgGroup, Id};
5719625d8cSopenharmony_ci/// let result = Command::new("cmd")
5819625d8cSopenharmony_ci///     .arg(arg!(--"set-ver" <ver> "set the version manually"))
5919625d8cSopenharmony_ci///     .arg(arg!(--major           "auto increase major"))
6019625d8cSopenharmony_ci///     .arg(arg!(--minor           "auto increase minor"))
6119625d8cSopenharmony_ci///     .arg(arg!(--patch           "auto increase patch"))
6219625d8cSopenharmony_ci///     .group(ArgGroup::new("vers")
6319625d8cSopenharmony_ci///          .args(["set-ver", "major", "minor","patch"])
6419625d8cSopenharmony_ci///          .required(true))
6519625d8cSopenharmony_ci///     .try_get_matches_from(vec!["cmd", "--major"]);
6619625d8cSopenharmony_ci/// assert!(result.is_ok());
6719625d8cSopenharmony_ci/// let matches = result.unwrap();
6819625d8cSopenharmony_ci/// // We may not know which of the args was used, so we can test for the group...
6919625d8cSopenharmony_ci/// assert!(matches.contains_id("vers"));
7019625d8cSopenharmony_ci/// // We can also ask the group which arg was used
7119625d8cSopenharmony_ci/// assert_eq!(matches
7219625d8cSopenharmony_ci///     .get_one::<Id>("vers")
7319625d8cSopenharmony_ci///     .expect("`vers` is required")
7419625d8cSopenharmony_ci///     .as_str(),
7519625d8cSopenharmony_ci///     "major"
7619625d8cSopenharmony_ci/// );
7719625d8cSopenharmony_ci/// // we could also alternatively check each arg individually (not shown here)
7819625d8cSopenharmony_ci/// ```
7919625d8cSopenharmony_ci/// [`ArgGroup::multiple(true)`]: ArgGroup::multiple()
8019625d8cSopenharmony_ci///
8119625d8cSopenharmony_ci/// [`ArgGroup::multiple(false)`]: ArgGroup::multiple()
8219625d8cSopenharmony_ci/// [arguments]: crate::Arg
8319625d8cSopenharmony_ci/// [conflict]: crate::Arg::conflicts_with()
8419625d8cSopenharmony_ci/// [requirement]: crate::Arg::requires()
8519625d8cSopenharmony_ci#[derive(Default, Clone, Debug, PartialEq, Eq)]
8619625d8cSopenharmony_cipub struct ArgGroup {
8719625d8cSopenharmony_ci    pub(crate) id: Id,
8819625d8cSopenharmony_ci    pub(crate) args: Vec<Id>,
8919625d8cSopenharmony_ci    pub(crate) required: bool,
9019625d8cSopenharmony_ci    pub(crate) requires: Vec<Id>,
9119625d8cSopenharmony_ci    pub(crate) conflicts: Vec<Id>,
9219625d8cSopenharmony_ci    pub(crate) multiple: bool,
9319625d8cSopenharmony_ci}
9419625d8cSopenharmony_ci
9519625d8cSopenharmony_ci/// # Builder
9619625d8cSopenharmony_ciimpl ArgGroup {
9719625d8cSopenharmony_ci    /// Create a `ArgGroup` using a unique name.
9819625d8cSopenharmony_ci    ///
9919625d8cSopenharmony_ci    /// The name will be used to get values from the group or refer to the group inside of conflict
10019625d8cSopenharmony_ci    /// and requirement rules.
10119625d8cSopenharmony_ci    ///
10219625d8cSopenharmony_ci    /// # Examples
10319625d8cSopenharmony_ci    ///
10419625d8cSopenharmony_ci    /// ```rust
10519625d8cSopenharmony_ci    /// # use clap::{Command, ArgGroup};
10619625d8cSopenharmony_ci    /// ArgGroup::new("config")
10719625d8cSopenharmony_ci    /// # ;
10819625d8cSopenharmony_ci    /// ```
10919625d8cSopenharmony_ci    pub fn new(id: impl Into<Id>) -> Self {
11019625d8cSopenharmony_ci        ArgGroup::default().id(id)
11119625d8cSopenharmony_ci    }
11219625d8cSopenharmony_ci
11319625d8cSopenharmony_ci    /// Sets the group name.
11419625d8cSopenharmony_ci    ///
11519625d8cSopenharmony_ci    /// # Examples
11619625d8cSopenharmony_ci    ///
11719625d8cSopenharmony_ci    /// ```rust
11819625d8cSopenharmony_ci    /// # use clap::{Command, ArgGroup};
11919625d8cSopenharmony_ci    /// ArgGroup::default().id("config")
12019625d8cSopenharmony_ci    /// # ;
12119625d8cSopenharmony_ci    /// ```
12219625d8cSopenharmony_ci    #[must_use]
12319625d8cSopenharmony_ci    pub fn id(mut self, id: impl Into<Id>) -> Self {
12419625d8cSopenharmony_ci        self.id = id.into();
12519625d8cSopenharmony_ci        self
12619625d8cSopenharmony_ci    }
12719625d8cSopenharmony_ci
12819625d8cSopenharmony_ci    /// Adds an [argument] to this group by name
12919625d8cSopenharmony_ci    ///
13019625d8cSopenharmony_ci    /// # Examples
13119625d8cSopenharmony_ci    ///
13219625d8cSopenharmony_ci    /// ```rust
13319625d8cSopenharmony_ci    /// # use clap::{Command, Arg, ArgGroup, ArgAction};
13419625d8cSopenharmony_ci    /// let m = Command::new("myprog")
13519625d8cSopenharmony_ci    ///     .arg(Arg::new("flag")
13619625d8cSopenharmony_ci    ///         .short('f')
13719625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
13819625d8cSopenharmony_ci    ///     .arg(Arg::new("color")
13919625d8cSopenharmony_ci    ///         .short('c')
14019625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
14119625d8cSopenharmony_ci    ///     .group(ArgGroup::new("req_flags")
14219625d8cSopenharmony_ci    ///         .arg("flag")
14319625d8cSopenharmony_ci    ///         .arg("color"))
14419625d8cSopenharmony_ci    ///     .get_matches_from(vec!["myprog", "-f"]);
14519625d8cSopenharmony_ci    /// // maybe we don't know which of the two flags was used...
14619625d8cSopenharmony_ci    /// assert!(m.contains_id("req_flags"));
14719625d8cSopenharmony_ci    /// // but we can also check individually if needed
14819625d8cSopenharmony_ci    /// assert!(m.contains_id("flag"));
14919625d8cSopenharmony_ci    /// ```
15019625d8cSopenharmony_ci    /// [argument]: crate::Arg
15119625d8cSopenharmony_ci    #[must_use]
15219625d8cSopenharmony_ci    pub fn arg(mut self, arg_id: impl IntoResettable<Id>) -> Self {
15319625d8cSopenharmony_ci        if let Some(arg_id) = arg_id.into_resettable().into_option() {
15419625d8cSopenharmony_ci            self.args.push(arg_id);
15519625d8cSopenharmony_ci        } else {
15619625d8cSopenharmony_ci            self.args.clear();
15719625d8cSopenharmony_ci        }
15819625d8cSopenharmony_ci        self
15919625d8cSopenharmony_ci    }
16019625d8cSopenharmony_ci
16119625d8cSopenharmony_ci    /// Adds multiple [arguments] to this group by name
16219625d8cSopenharmony_ci    ///
16319625d8cSopenharmony_ci    /// # Examples
16419625d8cSopenharmony_ci    ///
16519625d8cSopenharmony_ci    /// ```rust
16619625d8cSopenharmony_ci    /// # use clap::{Command, Arg, ArgGroup, ArgAction};
16719625d8cSopenharmony_ci    /// let m = Command::new("myprog")
16819625d8cSopenharmony_ci    ///     .arg(Arg::new("flag")
16919625d8cSopenharmony_ci    ///         .short('f')
17019625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
17119625d8cSopenharmony_ci    ///     .arg(Arg::new("color")
17219625d8cSopenharmony_ci    ///         .short('c')
17319625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
17419625d8cSopenharmony_ci    ///     .group(ArgGroup::new("req_flags")
17519625d8cSopenharmony_ci    ///         .args(["flag", "color"]))
17619625d8cSopenharmony_ci    ///     .get_matches_from(vec!["myprog", "-f"]);
17719625d8cSopenharmony_ci    /// // maybe we don't know which of the two flags was used...
17819625d8cSopenharmony_ci    /// assert!(m.contains_id("req_flags"));
17919625d8cSopenharmony_ci    /// // but we can also check individually if needed
18019625d8cSopenharmony_ci    /// assert!(m.contains_id("flag"));
18119625d8cSopenharmony_ci    /// ```
18219625d8cSopenharmony_ci    /// [arguments]: crate::Arg
18319625d8cSopenharmony_ci    #[must_use]
18419625d8cSopenharmony_ci    pub fn args(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
18519625d8cSopenharmony_ci        for n in ns {
18619625d8cSopenharmony_ci            self = self.arg(n);
18719625d8cSopenharmony_ci        }
18819625d8cSopenharmony_ci        self
18919625d8cSopenharmony_ci    }
19019625d8cSopenharmony_ci
19119625d8cSopenharmony_ci    /// Getters for all args. It will return a vector of `Id`
19219625d8cSopenharmony_ci    ///
19319625d8cSopenharmony_ci    /// # Example
19419625d8cSopenharmony_ci    ///
19519625d8cSopenharmony_ci    /// ```rust
19619625d8cSopenharmony_ci    /// # use clap::{ArgGroup};
19719625d8cSopenharmony_ci    /// let args: Vec<&str> = vec!["a1".into(), "a4".into()];
19819625d8cSopenharmony_ci    /// let grp = ArgGroup::new("program").args(&args);
19919625d8cSopenharmony_ci    ///
20019625d8cSopenharmony_ci    /// for (pos, arg) in grp.get_args().enumerate() {
20119625d8cSopenharmony_ci    ///     assert_eq!(*arg, args[pos]);
20219625d8cSopenharmony_ci    /// }
20319625d8cSopenharmony_ci    /// ```
20419625d8cSopenharmony_ci    pub fn get_args(&self) -> impl Iterator<Item = &Id> {
20519625d8cSopenharmony_ci        self.args.iter()
20619625d8cSopenharmony_ci    }
20719625d8cSopenharmony_ci
20819625d8cSopenharmony_ci    /// Allows more than one of the [`Arg`]s in this group to be used. (Default: `false`)
20919625d8cSopenharmony_ci    ///
21019625d8cSopenharmony_ci    /// # Examples
21119625d8cSopenharmony_ci    ///
21219625d8cSopenharmony_ci    /// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the
21319625d8cSopenharmony_ci    /// group
21419625d8cSopenharmony_ci    ///
21519625d8cSopenharmony_ci    /// ```rust
21619625d8cSopenharmony_ci    /// # use clap::{Command, Arg, ArgGroup, ArgAction};
21719625d8cSopenharmony_ci    /// let m = Command::new("myprog")
21819625d8cSopenharmony_ci    ///     .arg(Arg::new("flag")
21919625d8cSopenharmony_ci    ///         .short('f')
22019625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
22119625d8cSopenharmony_ci    ///     .arg(Arg::new("color")
22219625d8cSopenharmony_ci    ///         .short('c')
22319625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
22419625d8cSopenharmony_ci    ///     .group(ArgGroup::new("req_flags")
22519625d8cSopenharmony_ci    ///         .args(["flag", "color"])
22619625d8cSopenharmony_ci    ///         .multiple(true))
22719625d8cSopenharmony_ci    ///     .get_matches_from(vec!["myprog", "-f", "-c"]);
22819625d8cSopenharmony_ci    /// // maybe we don't know which of the two flags was used...
22919625d8cSopenharmony_ci    /// assert!(m.contains_id("req_flags"));
23019625d8cSopenharmony_ci    /// ```
23119625d8cSopenharmony_ci    /// In this next example, we show the default behavior (i.e. `multiple(false)) which will throw
23219625d8cSopenharmony_ci    /// an error if more than one of the args in the group was used.
23319625d8cSopenharmony_ci    ///
23419625d8cSopenharmony_ci    /// ```rust
23519625d8cSopenharmony_ci    /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
23619625d8cSopenharmony_ci    /// let result = Command::new("myprog")
23719625d8cSopenharmony_ci    ///     .arg(Arg::new("flag")
23819625d8cSopenharmony_ci    ///         .short('f')
23919625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
24019625d8cSopenharmony_ci    ///     .arg(Arg::new("color")
24119625d8cSopenharmony_ci    ///         .short('c')
24219625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
24319625d8cSopenharmony_ci    ///     .group(ArgGroup::new("req_flags")
24419625d8cSopenharmony_ci    ///         .args(["flag", "color"]))
24519625d8cSopenharmony_ci    ///     .try_get_matches_from(vec!["myprog", "-f", "-c"]);
24619625d8cSopenharmony_ci    /// // Because we used both args in the group it's an error
24719625d8cSopenharmony_ci    /// assert!(result.is_err());
24819625d8cSopenharmony_ci    /// let err = result.unwrap_err();
24919625d8cSopenharmony_ci    /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
25019625d8cSopenharmony_ci    /// ```
25119625d8cSopenharmony_ci    ///
25219625d8cSopenharmony_ci    /// [`Arg`]: crate::Arg
25319625d8cSopenharmony_ci    #[inline]
25419625d8cSopenharmony_ci    #[must_use]
25519625d8cSopenharmony_ci    pub fn multiple(mut self, yes: bool) -> Self {
25619625d8cSopenharmony_ci        self.multiple = yes;
25719625d8cSopenharmony_ci        self
25819625d8cSopenharmony_ci    }
25919625d8cSopenharmony_ci
26019625d8cSopenharmony_ci    /// Return true if the group allows more than one of the arguments
26119625d8cSopenharmony_ci    /// in this group to be used. (Default: `false`)
26219625d8cSopenharmony_ci    ///
26319625d8cSopenharmony_ci    /// # Example
26419625d8cSopenharmony_ci    ///
26519625d8cSopenharmony_ci    /// ```rust
26619625d8cSopenharmony_ci    /// # use clap::{ArgGroup};
26719625d8cSopenharmony_ci    /// let mut group = ArgGroup::new("myprog")
26819625d8cSopenharmony_ci    ///     .args(["f", "c"])
26919625d8cSopenharmony_ci    ///     .multiple(true);
27019625d8cSopenharmony_ci    ///
27119625d8cSopenharmony_ci    /// assert!(group.is_multiple());
27219625d8cSopenharmony_ci    /// ```
27319625d8cSopenharmony_ci    pub fn is_multiple(&mut self) -> bool {
27419625d8cSopenharmony_ci        self.multiple
27519625d8cSopenharmony_ci    }
27619625d8cSopenharmony_ci
27719625d8cSopenharmony_ci    /// Require an argument from the group to be present when parsing.
27819625d8cSopenharmony_ci    ///
27919625d8cSopenharmony_ci    /// This is unless conflicting with another argument.  A required group will be displayed in
28019625d8cSopenharmony_ci    /// the usage string of the application in the format `<arg|arg2|arg3>`.
28119625d8cSopenharmony_ci    ///
28219625d8cSopenharmony_ci    /// **NOTE:** This setting only applies to the current [`Command`] / [`Subcommand`]s, and not
28319625d8cSopenharmony_ci    /// globally.
28419625d8cSopenharmony_ci    ///
28519625d8cSopenharmony_ci    /// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with
28619625d8cSopenharmony_ci    /// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group.
28719625d8cSopenharmony_ci    /// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which
28819625d8cSopenharmony_ci    /// states, '*At least* one arg from this group must be used. Using multiple is OK."
28919625d8cSopenharmony_ci    ///
29019625d8cSopenharmony_ci    /// # Examples
29119625d8cSopenharmony_ci    ///
29219625d8cSopenharmony_ci    /// ```rust
29319625d8cSopenharmony_ci    /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
29419625d8cSopenharmony_ci    /// let result = Command::new("myprog")
29519625d8cSopenharmony_ci    ///     .arg(Arg::new("flag")
29619625d8cSopenharmony_ci    ///         .short('f')
29719625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
29819625d8cSopenharmony_ci    ///     .arg(Arg::new("color")
29919625d8cSopenharmony_ci    ///         .short('c')
30019625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
30119625d8cSopenharmony_ci    ///     .group(ArgGroup::new("req_flags")
30219625d8cSopenharmony_ci    ///         .args(["flag", "color"])
30319625d8cSopenharmony_ci    ///         .required(true))
30419625d8cSopenharmony_ci    ///     .try_get_matches_from(vec!["myprog"]);
30519625d8cSopenharmony_ci    /// // Because we didn't use any of the args in the group, it's an error
30619625d8cSopenharmony_ci    /// assert!(result.is_err());
30719625d8cSopenharmony_ci    /// let err = result.unwrap_err();
30819625d8cSopenharmony_ci    /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
30919625d8cSopenharmony_ci    /// ```
31019625d8cSopenharmony_ci    ///
31119625d8cSopenharmony_ci    /// [`Subcommand`]: crate::Subcommand
31219625d8cSopenharmony_ci    /// [`ArgGroup::multiple`]: ArgGroup::multiple()
31319625d8cSopenharmony_ci    /// [`Command`]: crate::Command
31419625d8cSopenharmony_ci    #[inline]
31519625d8cSopenharmony_ci    #[must_use]
31619625d8cSopenharmony_ci    pub fn required(mut self, yes: bool) -> Self {
31719625d8cSopenharmony_ci        self.required = yes;
31819625d8cSopenharmony_ci        self
31919625d8cSopenharmony_ci    }
32019625d8cSopenharmony_ci
32119625d8cSopenharmony_ci    /// Specify an argument or group that must be present when this group is.
32219625d8cSopenharmony_ci    ///
32319625d8cSopenharmony_ci    /// This is not to be confused with a [required group]. Requirement rules function just like
32419625d8cSopenharmony_ci    /// [argument requirement rules], you can name other arguments or groups that must be present
32519625d8cSopenharmony_ci    /// when any one of the arguments from this group is used.
32619625d8cSopenharmony_ci    ///
32719625d8cSopenharmony_ci    /// **NOTE:** The name provided may be an argument or group name
32819625d8cSopenharmony_ci    ///
32919625d8cSopenharmony_ci    /// # Examples
33019625d8cSopenharmony_ci    ///
33119625d8cSopenharmony_ci    /// ```rust
33219625d8cSopenharmony_ci    /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
33319625d8cSopenharmony_ci    /// let result = Command::new("myprog")
33419625d8cSopenharmony_ci    ///     .arg(Arg::new("flag")
33519625d8cSopenharmony_ci    ///         .short('f')
33619625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
33719625d8cSopenharmony_ci    ///     .arg(Arg::new("color")
33819625d8cSopenharmony_ci    ///         .short('c')
33919625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
34019625d8cSopenharmony_ci    ///     .arg(Arg::new("debug")
34119625d8cSopenharmony_ci    ///         .short('d')
34219625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
34319625d8cSopenharmony_ci    ///     .group(ArgGroup::new("req_flags")
34419625d8cSopenharmony_ci    ///         .args(["flag", "color"])
34519625d8cSopenharmony_ci    ///         .requires("debug"))
34619625d8cSopenharmony_ci    ///     .try_get_matches_from(vec!["myprog", "-c"]);
34719625d8cSopenharmony_ci    /// // because we used an arg from the group, and the group requires "-d" to be used, it's an
34819625d8cSopenharmony_ci    /// // error
34919625d8cSopenharmony_ci    /// assert!(result.is_err());
35019625d8cSopenharmony_ci    /// let err = result.unwrap_err();
35119625d8cSopenharmony_ci    /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
35219625d8cSopenharmony_ci    /// ```
35319625d8cSopenharmony_ci    /// [required group]: ArgGroup::required()
35419625d8cSopenharmony_ci    /// [argument requirement rules]: crate::Arg::requires()
35519625d8cSopenharmony_ci    #[must_use]
35619625d8cSopenharmony_ci    pub fn requires(mut self, id: impl IntoResettable<Id>) -> Self {
35719625d8cSopenharmony_ci        if let Some(id) = id.into_resettable().into_option() {
35819625d8cSopenharmony_ci            self.requires.push(id);
35919625d8cSopenharmony_ci        } else {
36019625d8cSopenharmony_ci            self.requires.clear();
36119625d8cSopenharmony_ci        }
36219625d8cSopenharmony_ci        self
36319625d8cSopenharmony_ci    }
36419625d8cSopenharmony_ci
36519625d8cSopenharmony_ci    /// Specify arguments or groups that must be present when this group is.
36619625d8cSopenharmony_ci    ///
36719625d8cSopenharmony_ci    /// This is not to be confused with a [required group]. Requirement rules function just like
36819625d8cSopenharmony_ci    /// [argument requirement rules], you can name other arguments or groups that must be present
36919625d8cSopenharmony_ci    /// when one of the arguments from this group is used.
37019625d8cSopenharmony_ci    ///
37119625d8cSopenharmony_ci    /// **NOTE:** The names provided may be an argument or group name
37219625d8cSopenharmony_ci    ///
37319625d8cSopenharmony_ci    /// # Examples
37419625d8cSopenharmony_ci    ///
37519625d8cSopenharmony_ci    /// ```rust
37619625d8cSopenharmony_ci    /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
37719625d8cSopenharmony_ci    /// let result = Command::new("myprog")
37819625d8cSopenharmony_ci    ///     .arg(Arg::new("flag")
37919625d8cSopenharmony_ci    ///         .short('f')
38019625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
38119625d8cSopenharmony_ci    ///     .arg(Arg::new("color")
38219625d8cSopenharmony_ci    ///         .short('c')
38319625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
38419625d8cSopenharmony_ci    ///     .arg(Arg::new("debug")
38519625d8cSopenharmony_ci    ///         .short('d')
38619625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
38719625d8cSopenharmony_ci    ///     .arg(Arg::new("verb")
38819625d8cSopenharmony_ci    ///         .short('v')
38919625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
39019625d8cSopenharmony_ci    ///     .group(ArgGroup::new("req_flags")
39119625d8cSopenharmony_ci    ///         .args(["flag", "color"])
39219625d8cSopenharmony_ci    ///         .requires_all(["debug", "verb"]))
39319625d8cSopenharmony_ci    ///     .try_get_matches_from(vec!["myprog", "-c", "-d"]);
39419625d8cSopenharmony_ci    /// // because we used an arg from the group, and the group requires "-d" and "-v" to be used,
39519625d8cSopenharmony_ci    /// // yet we only used "-d" it's an error
39619625d8cSopenharmony_ci    /// assert!(result.is_err());
39719625d8cSopenharmony_ci    /// let err = result.unwrap_err();
39819625d8cSopenharmony_ci    /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
39919625d8cSopenharmony_ci    /// ```
40019625d8cSopenharmony_ci    /// [required group]: ArgGroup::required()
40119625d8cSopenharmony_ci    /// [argument requirement rules]: crate::Arg::requires_ifs()
40219625d8cSopenharmony_ci    #[must_use]
40319625d8cSopenharmony_ci    pub fn requires_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
40419625d8cSopenharmony_ci        for n in ns {
40519625d8cSopenharmony_ci            self = self.requires(n);
40619625d8cSopenharmony_ci        }
40719625d8cSopenharmony_ci        self
40819625d8cSopenharmony_ci    }
40919625d8cSopenharmony_ci
41019625d8cSopenharmony_ci    /// Specify an argument or group that must **not** be present when this group is.
41119625d8cSopenharmony_ci    ///
41219625d8cSopenharmony_ci    /// Exclusion (aka conflict) rules function just like [argument exclusion rules], you can name
41319625d8cSopenharmony_ci    /// other arguments or groups that must *not* be present when one of the arguments from this
41419625d8cSopenharmony_ci    /// group are used.
41519625d8cSopenharmony_ci    ///
41619625d8cSopenharmony_ci    /// **NOTE:** The name provided may be an argument, or group name
41719625d8cSopenharmony_ci    ///
41819625d8cSopenharmony_ci    /// # Examples
41919625d8cSopenharmony_ci    ///
42019625d8cSopenharmony_ci    /// ```rust
42119625d8cSopenharmony_ci    /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
42219625d8cSopenharmony_ci    /// let result = Command::new("myprog")
42319625d8cSopenharmony_ci    ///     .arg(Arg::new("flag")
42419625d8cSopenharmony_ci    ///         .short('f')
42519625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
42619625d8cSopenharmony_ci    ///     .arg(Arg::new("color")
42719625d8cSopenharmony_ci    ///         .short('c')
42819625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
42919625d8cSopenharmony_ci    ///     .arg(Arg::new("debug")
43019625d8cSopenharmony_ci    ///         .short('d')
43119625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
43219625d8cSopenharmony_ci    ///     .group(ArgGroup::new("req_flags")
43319625d8cSopenharmony_ci    ///         .args(["flag", "color"])
43419625d8cSopenharmony_ci    ///         .conflicts_with("debug"))
43519625d8cSopenharmony_ci    ///     .try_get_matches_from(vec!["myprog", "-c", "-d"]);
43619625d8cSopenharmony_ci    /// // because we used an arg from the group, and the group conflicts with "-d", it's an error
43719625d8cSopenharmony_ci    /// assert!(result.is_err());
43819625d8cSopenharmony_ci    /// let err = result.unwrap_err();
43919625d8cSopenharmony_ci    /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
44019625d8cSopenharmony_ci    /// ```
44119625d8cSopenharmony_ci    /// [argument exclusion rules]: crate::Arg::conflicts_with()
44219625d8cSopenharmony_ci    #[must_use]
44319625d8cSopenharmony_ci    pub fn conflicts_with(mut self, id: impl IntoResettable<Id>) -> Self {
44419625d8cSopenharmony_ci        if let Some(id) = id.into_resettable().into_option() {
44519625d8cSopenharmony_ci            self.conflicts.push(id);
44619625d8cSopenharmony_ci        } else {
44719625d8cSopenharmony_ci            self.conflicts.clear();
44819625d8cSopenharmony_ci        }
44919625d8cSopenharmony_ci        self
45019625d8cSopenharmony_ci    }
45119625d8cSopenharmony_ci
45219625d8cSopenharmony_ci    /// Specify arguments or groups that must **not** be present when this group is.
45319625d8cSopenharmony_ci    ///
45419625d8cSopenharmony_ci    /// Exclusion rules function just like [argument exclusion rules], you can name other arguments
45519625d8cSopenharmony_ci    /// or groups that must *not* be present when one of the arguments from this group are used.
45619625d8cSopenharmony_ci    ///
45719625d8cSopenharmony_ci    /// **NOTE:** The names provided may be an argument, or group name
45819625d8cSopenharmony_ci    ///
45919625d8cSopenharmony_ci    /// # Examples
46019625d8cSopenharmony_ci    ///
46119625d8cSopenharmony_ci    /// ```rust
46219625d8cSopenharmony_ci    /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
46319625d8cSopenharmony_ci    /// let result = Command::new("myprog")
46419625d8cSopenharmony_ci    ///     .arg(Arg::new("flag")
46519625d8cSopenharmony_ci    ///         .short('f')
46619625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
46719625d8cSopenharmony_ci    ///     .arg(Arg::new("color")
46819625d8cSopenharmony_ci    ///         .short('c')
46919625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
47019625d8cSopenharmony_ci    ///     .arg(Arg::new("debug")
47119625d8cSopenharmony_ci    ///         .short('d')
47219625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
47319625d8cSopenharmony_ci    ///     .arg(Arg::new("verb")
47419625d8cSopenharmony_ci    ///         .short('v')
47519625d8cSopenharmony_ci    ///         .action(ArgAction::SetTrue))
47619625d8cSopenharmony_ci    ///     .group(ArgGroup::new("req_flags")
47719625d8cSopenharmony_ci    ///         .args(["flag", "color"])
47819625d8cSopenharmony_ci    ///         .conflicts_with_all(["debug", "verb"]))
47919625d8cSopenharmony_ci    ///     .try_get_matches_from(vec!["myprog", "-c", "-v"]);
48019625d8cSopenharmony_ci    /// // because we used an arg from the group, and the group conflicts with either "-v" or "-d"
48119625d8cSopenharmony_ci    /// // it's an error
48219625d8cSopenharmony_ci    /// assert!(result.is_err());
48319625d8cSopenharmony_ci    /// let err = result.unwrap_err();
48419625d8cSopenharmony_ci    /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
48519625d8cSopenharmony_ci    /// ```
48619625d8cSopenharmony_ci    ///
48719625d8cSopenharmony_ci    /// [argument exclusion rules]: crate::Arg::conflicts_with_all()
48819625d8cSopenharmony_ci    #[must_use]
48919625d8cSopenharmony_ci    pub fn conflicts_with_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
49019625d8cSopenharmony_ci        for n in ns {
49119625d8cSopenharmony_ci            self = self.conflicts_with(n);
49219625d8cSopenharmony_ci        }
49319625d8cSopenharmony_ci        self
49419625d8cSopenharmony_ci    }
49519625d8cSopenharmony_ci}
49619625d8cSopenharmony_ci
49719625d8cSopenharmony_ci/// # Reflection
49819625d8cSopenharmony_ciimpl ArgGroup {
49919625d8cSopenharmony_ci    /// Get the name of the group
50019625d8cSopenharmony_ci    #[inline]
50119625d8cSopenharmony_ci    pub fn get_id(&self) -> &Id {
50219625d8cSopenharmony_ci        &self.id
50319625d8cSopenharmony_ci    }
50419625d8cSopenharmony_ci
50519625d8cSopenharmony_ci    /// Reports whether [`ArgGroup::required`] is set
50619625d8cSopenharmony_ci    #[inline]
50719625d8cSopenharmony_ci    pub fn is_required_set(&self) -> bool {
50819625d8cSopenharmony_ci        self.required
50919625d8cSopenharmony_ci    }
51019625d8cSopenharmony_ci}
51119625d8cSopenharmony_ci
51219625d8cSopenharmony_ciimpl From<&'_ ArgGroup> for ArgGroup {
51319625d8cSopenharmony_ci    fn from(g: &ArgGroup) -> Self {
51419625d8cSopenharmony_ci        g.clone()
51519625d8cSopenharmony_ci    }
51619625d8cSopenharmony_ci}
51719625d8cSopenharmony_ci
51819625d8cSopenharmony_ci#[cfg(test)]
51919625d8cSopenharmony_cimod test {
52019625d8cSopenharmony_ci    use super::*;
52119625d8cSopenharmony_ci
52219625d8cSopenharmony_ci    #[test]
52319625d8cSopenharmony_ci    fn groups() {
52419625d8cSopenharmony_ci        let g = ArgGroup::new("test")
52519625d8cSopenharmony_ci            .arg("a1")
52619625d8cSopenharmony_ci            .arg("a4")
52719625d8cSopenharmony_ci            .args(["a2", "a3"])
52819625d8cSopenharmony_ci            .required(true)
52919625d8cSopenharmony_ci            .conflicts_with("c1")
53019625d8cSopenharmony_ci            .conflicts_with_all(["c2", "c3"])
53119625d8cSopenharmony_ci            .conflicts_with("c4")
53219625d8cSopenharmony_ci            .requires("r1")
53319625d8cSopenharmony_ci            .requires_all(["r2", "r3"])
53419625d8cSopenharmony_ci            .requires("r4");
53519625d8cSopenharmony_ci
53619625d8cSopenharmony_ci        let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()];
53719625d8cSopenharmony_ci        let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()];
53819625d8cSopenharmony_ci        let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()];
53919625d8cSopenharmony_ci
54019625d8cSopenharmony_ci        assert_eq!(g.args, args);
54119625d8cSopenharmony_ci        assert_eq!(g.requires, reqs);
54219625d8cSopenharmony_ci        assert_eq!(g.conflicts, confs);
54319625d8cSopenharmony_ci    }
54419625d8cSopenharmony_ci
54519625d8cSopenharmony_ci    #[test]
54619625d8cSopenharmony_ci    fn test_from() {
54719625d8cSopenharmony_ci        let g = ArgGroup::new("test")
54819625d8cSopenharmony_ci            .arg("a1")
54919625d8cSopenharmony_ci            .arg("a4")
55019625d8cSopenharmony_ci            .args(["a2", "a3"])
55119625d8cSopenharmony_ci            .required(true)
55219625d8cSopenharmony_ci            .conflicts_with("c1")
55319625d8cSopenharmony_ci            .conflicts_with_all(["c2", "c3"])
55419625d8cSopenharmony_ci            .conflicts_with("c4")
55519625d8cSopenharmony_ci            .requires("r1")
55619625d8cSopenharmony_ci            .requires_all(["r2", "r3"])
55719625d8cSopenharmony_ci            .requires("r4");
55819625d8cSopenharmony_ci
55919625d8cSopenharmony_ci        let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()];
56019625d8cSopenharmony_ci        let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()];
56119625d8cSopenharmony_ci        let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()];
56219625d8cSopenharmony_ci
56319625d8cSopenharmony_ci        let g2 = ArgGroup::from(&g);
56419625d8cSopenharmony_ci        assert_eq!(g2.args, args);
56519625d8cSopenharmony_ci        assert_eq!(g2.requires, reqs);
56619625d8cSopenharmony_ci        assert_eq!(g2.conflicts, confs);
56719625d8cSopenharmony_ci    }
56819625d8cSopenharmony_ci
56919625d8cSopenharmony_ci    // This test will *fail to compile* if ArgGroup is not Send + Sync
57019625d8cSopenharmony_ci    #[test]
57119625d8cSopenharmony_ci    fn arg_group_send_sync() {
57219625d8cSopenharmony_ci        fn foo<T: Send + Sync>(_: T) {}
57319625d8cSopenharmony_ci        foo(ArgGroup::new("test"))
57419625d8cSopenharmony_ci    }
57519625d8cSopenharmony_ci
57619625d8cSopenharmony_ci    #[test]
57719625d8cSopenharmony_ci    fn arg_group_expose_is_multiple_helper() {
57819625d8cSopenharmony_ci        let args: Vec<Id> = vec!["a1".into(), "a4".into()];
57919625d8cSopenharmony_ci
58019625d8cSopenharmony_ci        let mut grp_multiple = ArgGroup::new("test_multiple").args(&args).multiple(true);
58119625d8cSopenharmony_ci        assert!(grp_multiple.is_multiple());
58219625d8cSopenharmony_ci
58319625d8cSopenharmony_ci        let mut grp_not_multiple = ArgGroup::new("test_multiple").args(&args).multiple(false);
58419625d8cSopenharmony_ci        assert!(!grp_not_multiple.is_multiple());
58519625d8cSopenharmony_ci    }
58619625d8cSopenharmony_ci
58719625d8cSopenharmony_ci    #[test]
58819625d8cSopenharmony_ci    fn arg_group_expose_get_args_helper() {
58919625d8cSopenharmony_ci        let args: Vec<Id> = vec!["a1".into(), "a4".into()];
59019625d8cSopenharmony_ci        let grp = ArgGroup::new("program").args(&args);
59119625d8cSopenharmony_ci
59219625d8cSopenharmony_ci        for (pos, arg) in grp.get_args().enumerate() {
59319625d8cSopenharmony_ci            assert_eq!(*arg, args[pos]);
59419625d8cSopenharmony_ci        }
59519625d8cSopenharmony_ci    }
59619625d8cSopenharmony_ci}
597