119625d8cSopenharmony_ciuse std::cmp::Ordering;
219625d8cSopenharmony_ci
319625d8cSopenharmony_ciuse clap_lex::RawOsStr;
419625d8cSopenharmony_ci
519625d8cSopenharmony_ciuse crate::builder::OsStr;
619625d8cSopenharmony_ciuse crate::builder::ValueRange;
719625d8cSopenharmony_ciuse crate::mkeymap::KeyType;
819625d8cSopenharmony_ciuse crate::util::FlatSet;
919625d8cSopenharmony_ciuse crate::util::Id;
1019625d8cSopenharmony_ciuse crate::ArgAction;
1119625d8cSopenharmony_ciuse crate::INTERNAL_ERROR_MSG;
1219625d8cSopenharmony_ciuse crate::{Arg, Command, ValueHint};
1319625d8cSopenharmony_ci
1419625d8cSopenharmony_cipub(crate) fn assert_app(cmd: &Command) {
1519625d8cSopenharmony_ci    debug!("Command::_debug_asserts");
1619625d8cSopenharmony_ci
1719625d8cSopenharmony_ci    let mut short_flags = vec![];
1819625d8cSopenharmony_ci    let mut long_flags = vec![];
1919625d8cSopenharmony_ci
2019625d8cSopenharmony_ci    // Invalid version flag settings
2119625d8cSopenharmony_ci    if cmd.get_version().is_none() && cmd.get_long_version().is_none() {
2219625d8cSopenharmony_ci        // PropagateVersion is meaningless if there is no version
2319625d8cSopenharmony_ci        assert!(
2419625d8cSopenharmony_ci            !cmd.is_propagate_version_set(),
2519625d8cSopenharmony_ci            "Command {}: No version information via Command::version or Command::long_version to propagate",
2619625d8cSopenharmony_ci            cmd.get_name(),
2719625d8cSopenharmony_ci        );
2819625d8cSopenharmony_ci
2919625d8cSopenharmony_ci        // Used `Command::mut_arg("version", ..) but did not provide any version information to display
3019625d8cSopenharmony_ci        let version_needed = cmd
3119625d8cSopenharmony_ci            .get_arguments()
3219625d8cSopenharmony_ci            .filter(|x| matches!(x.get_action(), ArgAction::Version))
3319625d8cSopenharmony_ci            .map(|x| x.get_id())
3419625d8cSopenharmony_ci            .collect::<Vec<_>>();
3519625d8cSopenharmony_ci
3619625d8cSopenharmony_ci        assert_eq!(version_needed, Vec::<&str>::new(), "Command {}: `ArgAction::Version` used without providing Command::version or Command::long_version"
3719625d8cSopenharmony_ci            ,cmd.get_name()
3819625d8cSopenharmony_ci        );
3919625d8cSopenharmony_ci    }
4019625d8cSopenharmony_ci
4119625d8cSopenharmony_ci    for sc in cmd.get_subcommands() {
4219625d8cSopenharmony_ci        if let Some(s) = sc.get_short_flag().as_ref() {
4319625d8cSopenharmony_ci            short_flags.push(Flag::Command(format!("-{s}"), sc.get_name()));
4419625d8cSopenharmony_ci        }
4519625d8cSopenharmony_ci
4619625d8cSopenharmony_ci        for short_alias in sc.get_all_short_flag_aliases() {
4719625d8cSopenharmony_ci            short_flags.push(Flag::Command(format!("-{short_alias}"), sc.get_name()));
4819625d8cSopenharmony_ci        }
4919625d8cSopenharmony_ci
5019625d8cSopenharmony_ci        if let Some(l) = sc.get_long_flag().as_ref() {
5119625d8cSopenharmony_ci            assert!(!l.starts_with('-'), "Command {}: long_flag {:?} must not start with a `-`, that will be handled by the parser", sc.get_name(), l);
5219625d8cSopenharmony_ci            long_flags.push(Flag::Command(format!("--{l}"), sc.get_name()));
5319625d8cSopenharmony_ci        }
5419625d8cSopenharmony_ci
5519625d8cSopenharmony_ci        for long_alias in sc.get_all_long_flag_aliases() {
5619625d8cSopenharmony_ci            long_flags.push(Flag::Command(format!("--{long_alias}"), sc.get_name()));
5719625d8cSopenharmony_ci        }
5819625d8cSopenharmony_ci    }
5919625d8cSopenharmony_ci
6019625d8cSopenharmony_ci    for arg in cmd.get_arguments() {
6119625d8cSopenharmony_ci        assert_arg(arg);
6219625d8cSopenharmony_ci
6319625d8cSopenharmony_ci        assert!(
6419625d8cSopenharmony_ci            !cmd.is_multicall_set(),
6519625d8cSopenharmony_ci            "Command {}: Arguments like {} cannot be set on a multicall command",
6619625d8cSopenharmony_ci            cmd.get_name(),
6719625d8cSopenharmony_ci            arg.get_id()
6819625d8cSopenharmony_ci        );
6919625d8cSopenharmony_ci
7019625d8cSopenharmony_ci        if let Some(s) = arg.get_short() {
7119625d8cSopenharmony_ci            short_flags.push(Flag::Arg(format!("-{s}"), arg.get_id().as_str()));
7219625d8cSopenharmony_ci        }
7319625d8cSopenharmony_ci
7419625d8cSopenharmony_ci        for (short_alias, _) in &arg.short_aliases {
7519625d8cSopenharmony_ci            short_flags.push(Flag::Arg(format!("-{short_alias}"), arg.get_id().as_str()));
7619625d8cSopenharmony_ci        }
7719625d8cSopenharmony_ci
7819625d8cSopenharmony_ci        if let Some(l) = arg.get_long() {
7919625d8cSopenharmony_ci            assert!(!l.starts_with('-'), "Argument {}: long {:?} must not start with a `-`, that will be handled by the parser", arg.get_id(), l);
8019625d8cSopenharmony_ci            long_flags.push(Flag::Arg(format!("--{l}"), arg.get_id().as_str()));
8119625d8cSopenharmony_ci        }
8219625d8cSopenharmony_ci
8319625d8cSopenharmony_ci        for (long_alias, _) in &arg.aliases {
8419625d8cSopenharmony_ci            long_flags.push(Flag::Arg(format!("--{long_alias}"), arg.get_id().as_str()));
8519625d8cSopenharmony_ci        }
8619625d8cSopenharmony_ci
8719625d8cSopenharmony_ci        // Name conflicts
8819625d8cSopenharmony_ci        if let Some((first, second)) = cmd.two_args_of(|x| x.get_id() == arg.get_id()) {
8919625d8cSopenharmony_ci            panic!(
9019625d8cSopenharmony_ci            "Command {}: Argument names must be unique, but '{}' is in use by more than one argument or group{}",
9119625d8cSopenharmony_ci            cmd.get_name(),
9219625d8cSopenharmony_ci            arg.get_id(),
9319625d8cSopenharmony_ci            duplicate_tip(cmd, first, second),
9419625d8cSopenharmony_ci        );
9519625d8cSopenharmony_ci        }
9619625d8cSopenharmony_ci
9719625d8cSopenharmony_ci        // Long conflicts
9819625d8cSopenharmony_ci        if let Some(l) = arg.get_long() {
9919625d8cSopenharmony_ci            if let Some((first, second)) = cmd.two_args_of(|x| x.get_long() == Some(l)) {
10019625d8cSopenharmony_ci                panic!(
10119625d8cSopenharmony_ci                    "Command {}: Long option names must be unique for each argument, \
10219625d8cSopenharmony_ci                            but '--{}' is in use by both '{}' and '{}'{}",
10319625d8cSopenharmony_ci                    cmd.get_name(),
10419625d8cSopenharmony_ci                    l,
10519625d8cSopenharmony_ci                    first.get_id(),
10619625d8cSopenharmony_ci                    second.get_id(),
10719625d8cSopenharmony_ci                    duplicate_tip(cmd, first, second)
10819625d8cSopenharmony_ci                )
10919625d8cSopenharmony_ci            }
11019625d8cSopenharmony_ci        }
11119625d8cSopenharmony_ci
11219625d8cSopenharmony_ci        // Short conflicts
11319625d8cSopenharmony_ci        if let Some(s) = arg.get_short() {
11419625d8cSopenharmony_ci            if let Some((first, second)) = cmd.two_args_of(|x| x.get_short() == Some(s)) {
11519625d8cSopenharmony_ci                panic!(
11619625d8cSopenharmony_ci                    "Command {}: Short option names must be unique for each argument, \
11719625d8cSopenharmony_ci                            but '-{}' is in use by both '{}' and '{}'{}",
11819625d8cSopenharmony_ci                    cmd.get_name(),
11919625d8cSopenharmony_ci                    s,
12019625d8cSopenharmony_ci                    first.get_id(),
12119625d8cSopenharmony_ci                    second.get_id(),
12219625d8cSopenharmony_ci                    duplicate_tip(cmd, first, second),
12319625d8cSopenharmony_ci                )
12419625d8cSopenharmony_ci            }
12519625d8cSopenharmony_ci        }
12619625d8cSopenharmony_ci
12719625d8cSopenharmony_ci        // Index conflicts
12819625d8cSopenharmony_ci        if let Some(idx) = arg.index {
12919625d8cSopenharmony_ci            if let Some((first, second)) =
13019625d8cSopenharmony_ci                cmd.two_args_of(|x| x.is_positional() && x.get_index() == Some(idx))
13119625d8cSopenharmony_ci            {
13219625d8cSopenharmony_ci                panic!(
13319625d8cSopenharmony_ci                    "Command {}: Argument '{}' has the same index as '{}' \
13419625d8cSopenharmony_ci                    and they are both positional arguments\n\n\t \
13519625d8cSopenharmony_ci                    Use `Arg::num_args(1..)` to allow one \
13619625d8cSopenharmony_ci                    positional argument to take multiple values",
13719625d8cSopenharmony_ci                    cmd.get_name(),
13819625d8cSopenharmony_ci                    first.get_id(),
13919625d8cSopenharmony_ci                    second.get_id()
14019625d8cSopenharmony_ci                )
14119625d8cSopenharmony_ci            }
14219625d8cSopenharmony_ci        }
14319625d8cSopenharmony_ci
14419625d8cSopenharmony_ci        // requires, r_if, r_unless
14519625d8cSopenharmony_ci        for req in &arg.requires {
14619625d8cSopenharmony_ci            assert!(
14719625d8cSopenharmony_ci                cmd.id_exists(&req.1),
14819625d8cSopenharmony_ci                "Command {}: Argument or group '{}' specified in 'requires*' for '{}' does not exist",
14919625d8cSopenharmony_ci                cmd.get_name(),
15019625d8cSopenharmony_ci                req.1,
15119625d8cSopenharmony_ci                arg.get_id(),
15219625d8cSopenharmony_ci            );
15319625d8cSopenharmony_ci        }
15419625d8cSopenharmony_ci
15519625d8cSopenharmony_ci        for req in &arg.r_ifs {
15619625d8cSopenharmony_ci            assert!(
15719625d8cSopenharmony_ci                !arg.is_required_set(),
15819625d8cSopenharmony_ci                "Argument {}: `required` conflicts with `required_if_eq*`",
15919625d8cSopenharmony_ci                arg.get_id()
16019625d8cSopenharmony_ci            );
16119625d8cSopenharmony_ci            assert!(
16219625d8cSopenharmony_ci                cmd.id_exists(&req.0),
16319625d8cSopenharmony_ci                "Command {}: Argument or group '{}' specified in 'required_if_eq*' for '{}' does not exist",
16419625d8cSopenharmony_ci                    cmd.get_name(),
16519625d8cSopenharmony_ci                req.0,
16619625d8cSopenharmony_ci                arg.get_id()
16719625d8cSopenharmony_ci            );
16819625d8cSopenharmony_ci        }
16919625d8cSopenharmony_ci
17019625d8cSopenharmony_ci        for req in &arg.r_ifs_all {
17119625d8cSopenharmony_ci            assert!(
17219625d8cSopenharmony_ci                !arg.is_required_set(),
17319625d8cSopenharmony_ci                "Argument {}: `required` conflicts with `required_if_eq_all`",
17419625d8cSopenharmony_ci                arg.get_id()
17519625d8cSopenharmony_ci            );
17619625d8cSopenharmony_ci            assert!(
17719625d8cSopenharmony_ci                cmd.id_exists(&req.0),
17819625d8cSopenharmony_ci                "Command {}: Argument or group '{}' specified in 'required_if_eq_all' for '{}' does not exist",
17919625d8cSopenharmony_ci                    cmd.get_name(),
18019625d8cSopenharmony_ci                req.0,
18119625d8cSopenharmony_ci                arg.get_id()
18219625d8cSopenharmony_ci            );
18319625d8cSopenharmony_ci        }
18419625d8cSopenharmony_ci
18519625d8cSopenharmony_ci        for req in &arg.r_unless {
18619625d8cSopenharmony_ci            assert!(
18719625d8cSopenharmony_ci                !arg.is_required_set(),
18819625d8cSopenharmony_ci                "Argument {}: `required` conflicts with `required_unless*`",
18919625d8cSopenharmony_ci                arg.get_id()
19019625d8cSopenharmony_ci            );
19119625d8cSopenharmony_ci            assert!(
19219625d8cSopenharmony_ci                cmd.id_exists(req),
19319625d8cSopenharmony_ci                "Command {}: Argument or group '{}' specified in 'required_unless*' for '{}' does not exist",
19419625d8cSopenharmony_ci                    cmd.get_name(),
19519625d8cSopenharmony_ci                req,
19619625d8cSopenharmony_ci                arg.get_id(),
19719625d8cSopenharmony_ci            );
19819625d8cSopenharmony_ci        }
19919625d8cSopenharmony_ci
20019625d8cSopenharmony_ci        for req in &arg.r_unless_all {
20119625d8cSopenharmony_ci            assert!(
20219625d8cSopenharmony_ci                !arg.is_required_set(),
20319625d8cSopenharmony_ci                "Argument {}: `required` conflicts with `required_unless*`",
20419625d8cSopenharmony_ci                arg.get_id()
20519625d8cSopenharmony_ci            );
20619625d8cSopenharmony_ci            assert!(
20719625d8cSopenharmony_ci                cmd.id_exists(req),
20819625d8cSopenharmony_ci                "Command {}: Argument or group '{}' specified in 'required_unless*' for '{}' does not exist",
20919625d8cSopenharmony_ci                    cmd.get_name(),
21019625d8cSopenharmony_ci                req,
21119625d8cSopenharmony_ci                arg.get_id(),
21219625d8cSopenharmony_ci            );
21319625d8cSopenharmony_ci        }
21419625d8cSopenharmony_ci
21519625d8cSopenharmony_ci        // blacklist
21619625d8cSopenharmony_ci        for req in &arg.blacklist {
21719625d8cSopenharmony_ci            assert!(
21819625d8cSopenharmony_ci                cmd.id_exists(req),
21919625d8cSopenharmony_ci                "Command {}: Argument or group '{}' specified in 'conflicts_with*' for '{}' does not exist",
22019625d8cSopenharmony_ci                    cmd.get_name(),
22119625d8cSopenharmony_ci                req,
22219625d8cSopenharmony_ci                arg.get_id(),
22319625d8cSopenharmony_ci            );
22419625d8cSopenharmony_ci        }
22519625d8cSopenharmony_ci
22619625d8cSopenharmony_ci        // overrides
22719625d8cSopenharmony_ci        for req in &arg.overrides {
22819625d8cSopenharmony_ci            assert!(
22919625d8cSopenharmony_ci                cmd.id_exists(req),
23019625d8cSopenharmony_ci                "Command {}: Argument or group '{}' specified in 'overrides_with*' for '{}' does not exist",
23119625d8cSopenharmony_ci                    cmd.get_name(),
23219625d8cSopenharmony_ci                req,
23319625d8cSopenharmony_ci                arg.get_id(),
23419625d8cSopenharmony_ci            );
23519625d8cSopenharmony_ci        }
23619625d8cSopenharmony_ci
23719625d8cSopenharmony_ci        if arg.is_last_set() {
23819625d8cSopenharmony_ci            assert!(
23919625d8cSopenharmony_ci                arg.get_long().is_none(),
24019625d8cSopenharmony_ci                "Command {}: Flags or Options cannot have last(true) set. '{}' has both a long and last(true) set.",
24119625d8cSopenharmony_ci                    cmd.get_name(),
24219625d8cSopenharmony_ci                arg.get_id()
24319625d8cSopenharmony_ci            );
24419625d8cSopenharmony_ci            assert!(
24519625d8cSopenharmony_ci                arg.get_short().is_none(),
24619625d8cSopenharmony_ci                "Command {}: Flags or Options cannot have last(true) set. '{}' has both a short and last(true) set.",
24719625d8cSopenharmony_ci                    cmd.get_name(),
24819625d8cSopenharmony_ci                arg.get_id()
24919625d8cSopenharmony_ci            );
25019625d8cSopenharmony_ci        }
25119625d8cSopenharmony_ci
25219625d8cSopenharmony_ci        assert!(
25319625d8cSopenharmony_ci            !(arg.is_required_set() && arg.is_global_set()),
25419625d8cSopenharmony_ci            "Command {}: Global arguments cannot be required.\n\n\t'{}' is marked as both global and required",
25519625d8cSopenharmony_ci                    cmd.get_name(),
25619625d8cSopenharmony_ci            arg.get_id()
25719625d8cSopenharmony_ci        );
25819625d8cSopenharmony_ci
25919625d8cSopenharmony_ci        if arg.get_value_hint() == ValueHint::CommandWithArguments {
26019625d8cSopenharmony_ci            assert!(
26119625d8cSopenharmony_ci                arg.is_positional(),
26219625d8cSopenharmony_ci                "Command {}: Argument '{}' has hint CommandWithArguments and must be positional.",
26319625d8cSopenharmony_ci                cmd.get_name(),
26419625d8cSopenharmony_ci                arg.get_id()
26519625d8cSopenharmony_ci            );
26619625d8cSopenharmony_ci
26719625d8cSopenharmony_ci            assert!(
26819625d8cSopenharmony_ci                arg.is_trailing_var_arg_set() || arg.is_last_set(),
26919625d8cSopenharmony_ci                "Command {}: Positional argument '{}' has hint CommandWithArguments, so Command must have `trailing_var_arg(true)` or `last(true)` set.",
27019625d8cSopenharmony_ci                    cmd.get_name(),
27119625d8cSopenharmony_ci                arg.get_id()
27219625d8cSopenharmony_ci            );
27319625d8cSopenharmony_ci        }
27419625d8cSopenharmony_ci    }
27519625d8cSopenharmony_ci
27619625d8cSopenharmony_ci    for group in cmd.get_groups() {
27719625d8cSopenharmony_ci        let derive_hint = if cfg!(feature = "derive") {
27819625d8cSopenharmony_ci            " (note: `Args` implicitly creates `ArgGroup`s; disable with `#[group(skip)]`"
27919625d8cSopenharmony_ci        } else {
28019625d8cSopenharmony_ci            ""
28119625d8cSopenharmony_ci        };
28219625d8cSopenharmony_ci
28319625d8cSopenharmony_ci        // Name conflicts
28419625d8cSopenharmony_ci        assert!(
28519625d8cSopenharmony_ci            cmd.get_groups().filter(|x| x.id == group.id).count() < 2,
28619625d8cSopenharmony_ci            "Command {}: Argument group name must be unique\n\n\t'{}' is already in use{}",
28719625d8cSopenharmony_ci            cmd.get_name(),
28819625d8cSopenharmony_ci            group.get_id(),
28919625d8cSopenharmony_ci            derive_hint
29019625d8cSopenharmony_ci        );
29119625d8cSopenharmony_ci
29219625d8cSopenharmony_ci        // Groups should not have naming conflicts with Args
29319625d8cSopenharmony_ci        assert!(
29419625d8cSopenharmony_ci            !cmd.get_arguments().any(|x| x.get_id() == group.get_id()),
29519625d8cSopenharmony_ci            "Command {}: Argument group name '{}' must not conflict with argument name{}",
29619625d8cSopenharmony_ci            cmd.get_name(),
29719625d8cSopenharmony_ci            group.get_id(),
29819625d8cSopenharmony_ci            derive_hint
29919625d8cSopenharmony_ci        );
30019625d8cSopenharmony_ci
30119625d8cSopenharmony_ci        for arg in &group.args {
30219625d8cSopenharmony_ci            // Args listed inside groups should exist
30319625d8cSopenharmony_ci            assert!(
30419625d8cSopenharmony_ci                cmd.get_arguments().any(|x| x.get_id() == arg),
30519625d8cSopenharmony_ci                "Command {}: Argument group '{}' contains non-existent argument '{}'",
30619625d8cSopenharmony_ci                cmd.get_name(),
30719625d8cSopenharmony_ci                group.get_id(),
30819625d8cSopenharmony_ci                arg
30919625d8cSopenharmony_ci            );
31019625d8cSopenharmony_ci        }
31119625d8cSopenharmony_ci    }
31219625d8cSopenharmony_ci
31319625d8cSopenharmony_ci    // Conflicts between flags and subcommands
31419625d8cSopenharmony_ci
31519625d8cSopenharmony_ci    long_flags.sort_unstable();
31619625d8cSopenharmony_ci    short_flags.sort_unstable();
31719625d8cSopenharmony_ci
31819625d8cSopenharmony_ci    detect_duplicate_flags(&long_flags, "long");
31919625d8cSopenharmony_ci    detect_duplicate_flags(&short_flags, "short");
32019625d8cSopenharmony_ci
32119625d8cSopenharmony_ci    let mut subs = FlatSet::new();
32219625d8cSopenharmony_ci    for sc in cmd.get_subcommands() {
32319625d8cSopenharmony_ci        assert!(
32419625d8cSopenharmony_ci            subs.insert(sc.get_name()),
32519625d8cSopenharmony_ci            "Command {}: command name `{}` is duplicated",
32619625d8cSopenharmony_ci            cmd.get_name(),
32719625d8cSopenharmony_ci            sc.get_name()
32819625d8cSopenharmony_ci        );
32919625d8cSopenharmony_ci        for alias in sc.get_all_aliases() {
33019625d8cSopenharmony_ci            assert!(
33119625d8cSopenharmony_ci                subs.insert(alias),
33219625d8cSopenharmony_ci                "Command {}: command `{}` alias `{}` is duplicated",
33319625d8cSopenharmony_ci                cmd.get_name(),
33419625d8cSopenharmony_ci                sc.get_name(),
33519625d8cSopenharmony_ci                alias
33619625d8cSopenharmony_ci            );
33719625d8cSopenharmony_ci        }
33819625d8cSopenharmony_ci    }
33919625d8cSopenharmony_ci
34019625d8cSopenharmony_ci    _verify_positionals(cmd);
34119625d8cSopenharmony_ci
34219625d8cSopenharmony_ci    #[cfg(feature = "help")]
34319625d8cSopenharmony_ci    if let Some(help_template) = cmd.get_help_template() {
34419625d8cSopenharmony_ci        assert!(
34519625d8cSopenharmony_ci            !help_template.to_string().contains("{flags}"),
34619625d8cSopenharmony_ci            "Command {}: {}",
34719625d8cSopenharmony_ci                    cmd.get_name(),
34819625d8cSopenharmony_ci            "`{flags}` template variable was removed in clap3, they are now included in `{options}`",
34919625d8cSopenharmony_ci        );
35019625d8cSopenharmony_ci        assert!(
35119625d8cSopenharmony_ci            !help_template.to_string().contains("{unified}"),
35219625d8cSopenharmony_ci            "Command {}: {}",
35319625d8cSopenharmony_ci            cmd.get_name(),
35419625d8cSopenharmony_ci            "`{unified}` template variable was removed in clap3, use `{options}` instead"
35519625d8cSopenharmony_ci        );
35619625d8cSopenharmony_ci        #[cfg(feature = "unstable-v5")]
35719625d8cSopenharmony_ci        assert!(
35819625d8cSopenharmony_ci            !help_template.to_string().contains("{bin}"),
35919625d8cSopenharmony_ci            "Command {}: {}",
36019625d8cSopenharmony_ci            cmd.get_name(),
36119625d8cSopenharmony_ci            "`{bin}` template variable was removed in clap5, use `{name}` instead"
36219625d8cSopenharmony_ci        )
36319625d8cSopenharmony_ci    }
36419625d8cSopenharmony_ci
36519625d8cSopenharmony_ci    cmd._panic_on_missing_help(cmd.is_help_expected_set());
36619625d8cSopenharmony_ci    assert_app_flags(cmd);
36719625d8cSopenharmony_ci}
36819625d8cSopenharmony_ci
36919625d8cSopenharmony_cifn duplicate_tip(cmd: &Command, first: &Arg, second: &Arg) -> &'static str {
37019625d8cSopenharmony_ci    if !cmd.is_disable_help_flag_set()
37119625d8cSopenharmony_ci        && (first.get_id() == Id::HELP || second.get_id() == Id::HELP)
37219625d8cSopenharmony_ci    {
37319625d8cSopenharmony_ci        " (call `cmd.disable_help_flag(true)` to remove the auto-generated `--help`)"
37419625d8cSopenharmony_ci    } else if !cmd.is_disable_version_flag_set()
37519625d8cSopenharmony_ci        && (first.get_id() == Id::VERSION || second.get_id() == Id::VERSION)
37619625d8cSopenharmony_ci    {
37719625d8cSopenharmony_ci        " (call `cmd.disable_version_flag(true)` to remove the auto-generated `--version`)"
37819625d8cSopenharmony_ci    } else {
37919625d8cSopenharmony_ci        ""
38019625d8cSopenharmony_ci    }
38119625d8cSopenharmony_ci}
38219625d8cSopenharmony_ci
38319625d8cSopenharmony_ci#[derive(Eq)]
38419625d8cSopenharmony_cienum Flag<'a> {
38519625d8cSopenharmony_ci    Command(String, &'a str),
38619625d8cSopenharmony_ci    Arg(String, &'a str),
38719625d8cSopenharmony_ci}
38819625d8cSopenharmony_ci
38919625d8cSopenharmony_ciimpl PartialEq for Flag<'_> {
39019625d8cSopenharmony_ci    fn eq(&self, other: &Flag) -> bool {
39119625d8cSopenharmony_ci        self.cmp(other) == Ordering::Equal
39219625d8cSopenharmony_ci    }
39319625d8cSopenharmony_ci}
39419625d8cSopenharmony_ci
39519625d8cSopenharmony_ciimpl PartialOrd for Flag<'_> {
39619625d8cSopenharmony_ci    fn partial_cmp(&self, other: &Flag) -> Option<Ordering> {
39719625d8cSopenharmony_ci        use Flag::*;
39819625d8cSopenharmony_ci
39919625d8cSopenharmony_ci        match (self, other) {
40019625d8cSopenharmony_ci            (Command(s1, _), Command(s2, _))
40119625d8cSopenharmony_ci            | (Arg(s1, _), Arg(s2, _))
40219625d8cSopenharmony_ci            | (Command(s1, _), Arg(s2, _))
40319625d8cSopenharmony_ci            | (Arg(s1, _), Command(s2, _)) => {
40419625d8cSopenharmony_ci                if s1 == s2 {
40519625d8cSopenharmony_ci                    Some(Ordering::Equal)
40619625d8cSopenharmony_ci                } else {
40719625d8cSopenharmony_ci                    s1.partial_cmp(s2)
40819625d8cSopenharmony_ci                }
40919625d8cSopenharmony_ci            }
41019625d8cSopenharmony_ci        }
41119625d8cSopenharmony_ci    }
41219625d8cSopenharmony_ci}
41319625d8cSopenharmony_ci
41419625d8cSopenharmony_ciimpl Ord for Flag<'_> {
41519625d8cSopenharmony_ci    fn cmp(&self, other: &Self) -> Ordering {
41619625d8cSopenharmony_ci        self.partial_cmp(other).unwrap()
41719625d8cSopenharmony_ci    }
41819625d8cSopenharmony_ci}
41919625d8cSopenharmony_ci
42019625d8cSopenharmony_cifn detect_duplicate_flags(flags: &[Flag], short_or_long: &str) {
42119625d8cSopenharmony_ci    use Flag::*;
42219625d8cSopenharmony_ci
42319625d8cSopenharmony_ci    for (one, two) in find_duplicates(flags) {
42419625d8cSopenharmony_ci        match (one, two) {
42519625d8cSopenharmony_ci            (Command(flag, one), Command(_, another)) if one != another => panic!(
42619625d8cSopenharmony_ci                "the '{flag}' {short_or_long} flag is specified for both '{one}' and '{another}' subcommands"
42719625d8cSopenharmony_ci            ),
42819625d8cSopenharmony_ci
42919625d8cSopenharmony_ci            (Arg(flag, one), Arg(_, another)) if one != another => panic!(
43019625d8cSopenharmony_ci                "{short_or_long} option names must be unique, but '{flag}' is in use by both '{one}' and '{another}'"
43119625d8cSopenharmony_ci            ),
43219625d8cSopenharmony_ci
43319625d8cSopenharmony_ci            (Arg(flag, arg), Command(_, sub)) | (Command(flag, sub), Arg(_, arg)) => panic!(
43419625d8cSopenharmony_ci                "the '{flag}' {short_or_long} flag for the '{arg}' argument conflicts with the short flag \
43519625d8cSopenharmony_ci                     for '{sub}' subcommand"
43619625d8cSopenharmony_ci            ),
43719625d8cSopenharmony_ci
43819625d8cSopenharmony_ci            _ => {}
43919625d8cSopenharmony_ci        }
44019625d8cSopenharmony_ci    }
44119625d8cSopenharmony_ci}
44219625d8cSopenharmony_ci
44319625d8cSopenharmony_ci/// Find duplicates in a sorted array.
44419625d8cSopenharmony_ci///
44519625d8cSopenharmony_ci/// The algorithm is simple: the array is sorted, duplicates
44619625d8cSopenharmony_ci/// must be placed next to each other, we can check only adjacent elements.
44719625d8cSopenharmony_cifn find_duplicates<T: PartialEq>(slice: &[T]) -> impl Iterator<Item = (&T, &T)> {
44819625d8cSopenharmony_ci    slice.windows(2).filter_map(|w| {
44919625d8cSopenharmony_ci        if w[0] == w[1] {
45019625d8cSopenharmony_ci            Some((&w[0], &w[1]))
45119625d8cSopenharmony_ci        } else {
45219625d8cSopenharmony_ci            None
45319625d8cSopenharmony_ci        }
45419625d8cSopenharmony_ci    })
45519625d8cSopenharmony_ci}
45619625d8cSopenharmony_ci
45719625d8cSopenharmony_cifn assert_app_flags(cmd: &Command) {
45819625d8cSopenharmony_ci    macro_rules! checker {
45919625d8cSopenharmony_ci        ($a:ident requires $($b:ident)|+) => {
46019625d8cSopenharmony_ci            if cmd.$a() {
46119625d8cSopenharmony_ci                let mut s = String::new();
46219625d8cSopenharmony_ci
46319625d8cSopenharmony_ci                $(
46419625d8cSopenharmony_ci                    if !cmd.$b() {
46519625d8cSopenharmony_ci                        use std::fmt::Write;
46619625d8cSopenharmony_ci                        write!(&mut s, "  AppSettings::{} is required when AppSettings::{} is set.\n", std::stringify!($b), std::stringify!($a)).unwrap();
46719625d8cSopenharmony_ci                    }
46819625d8cSopenharmony_ci                )+
46919625d8cSopenharmony_ci
47019625d8cSopenharmony_ci                if !s.is_empty() {
47119625d8cSopenharmony_ci                    panic!("{}", s)
47219625d8cSopenharmony_ci                }
47319625d8cSopenharmony_ci            }
47419625d8cSopenharmony_ci        };
47519625d8cSopenharmony_ci        ($a:ident conflicts $($b:ident)|+) => {
47619625d8cSopenharmony_ci            if cmd.$a() {
47719625d8cSopenharmony_ci                let mut s = String::new();
47819625d8cSopenharmony_ci
47919625d8cSopenharmony_ci                $(
48019625d8cSopenharmony_ci                    if cmd.$b() {
48119625d8cSopenharmony_ci                        use std::fmt::Write;
48219625d8cSopenharmony_ci                        write!(&mut s, "  AppSettings::{} conflicts with AppSettings::{}.\n", std::stringify!($b), std::stringify!($a)).unwrap();
48319625d8cSopenharmony_ci                    }
48419625d8cSopenharmony_ci                )+
48519625d8cSopenharmony_ci
48619625d8cSopenharmony_ci                if !s.is_empty() {
48719625d8cSopenharmony_ci                    panic!("{}\n{}", cmd.get_name(), s)
48819625d8cSopenharmony_ci                }
48919625d8cSopenharmony_ci            }
49019625d8cSopenharmony_ci        };
49119625d8cSopenharmony_ci    }
49219625d8cSopenharmony_ci
49319625d8cSopenharmony_ci    checker!(is_multicall_set conflicts is_no_binary_name_set);
49419625d8cSopenharmony_ci}
49519625d8cSopenharmony_ci
49619625d8cSopenharmony_ci#[cfg(debug_assertions)]
49719625d8cSopenharmony_cifn _verify_positionals(cmd: &Command) -> bool {
49819625d8cSopenharmony_ci    debug!("Command::_verify_positionals");
49919625d8cSopenharmony_ci    // Because you must wait until all arguments have been supplied, this is the first chance
50019625d8cSopenharmony_ci    // to make assertions on positional argument indexes
50119625d8cSopenharmony_ci    //
50219625d8cSopenharmony_ci    // First we verify that the index highest supplied index, is equal to the number of
50319625d8cSopenharmony_ci    // positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
50419625d8cSopenharmony_ci    // but no 2)
50519625d8cSopenharmony_ci
50619625d8cSopenharmony_ci    let highest_idx = cmd
50719625d8cSopenharmony_ci        .get_keymap()
50819625d8cSopenharmony_ci        .keys()
50919625d8cSopenharmony_ci        .filter_map(|x| {
51019625d8cSopenharmony_ci            if let KeyType::Position(n) = x {
51119625d8cSopenharmony_ci                Some(*n)
51219625d8cSopenharmony_ci            } else {
51319625d8cSopenharmony_ci                None
51419625d8cSopenharmony_ci            }
51519625d8cSopenharmony_ci        })
51619625d8cSopenharmony_ci        .max()
51719625d8cSopenharmony_ci        .unwrap_or(0);
51819625d8cSopenharmony_ci
51919625d8cSopenharmony_ci    let num_p = cmd.get_keymap().keys().filter(|x| x.is_position()).count();
52019625d8cSopenharmony_ci
52119625d8cSopenharmony_ci    assert!(
52219625d8cSopenharmony_ci        highest_idx == num_p,
52319625d8cSopenharmony_ci        "Found positional argument whose index is {highest_idx} but there \
52419625d8cSopenharmony_ci             are only {num_p} positional arguments defined",
52519625d8cSopenharmony_ci    );
52619625d8cSopenharmony_ci
52719625d8cSopenharmony_ci    for arg in cmd.get_arguments() {
52819625d8cSopenharmony_ci        if arg.index.unwrap_or(0) == highest_idx {
52919625d8cSopenharmony_ci            assert!(
53019625d8cSopenharmony_ci                !arg.is_trailing_var_arg_set() || !arg.is_last_set(),
53119625d8cSopenharmony_ci                "{}:{}: `Arg::trailing_var_arg` and `Arg::last` cannot be used together",
53219625d8cSopenharmony_ci                cmd.get_name(),
53319625d8cSopenharmony_ci                arg.get_id()
53419625d8cSopenharmony_ci            );
53519625d8cSopenharmony_ci
53619625d8cSopenharmony_ci            if arg.is_trailing_var_arg_set() {
53719625d8cSopenharmony_ci                assert!(
53819625d8cSopenharmony_ci                    arg.is_multiple(),
53919625d8cSopenharmony_ci                    "{}:{}: `Arg::trailing_var_arg` must accept multiple values",
54019625d8cSopenharmony_ci                    cmd.get_name(),
54119625d8cSopenharmony_ci                    arg.get_id()
54219625d8cSopenharmony_ci                );
54319625d8cSopenharmony_ci            }
54419625d8cSopenharmony_ci        } else {
54519625d8cSopenharmony_ci            assert!(
54619625d8cSopenharmony_ci                !arg.is_trailing_var_arg_set(),
54719625d8cSopenharmony_ci                "{}:{}: `Arg::trailing_var_arg` can only apply to last positional",
54819625d8cSopenharmony_ci                cmd.get_name(),
54919625d8cSopenharmony_ci                arg.get_id()
55019625d8cSopenharmony_ci            );
55119625d8cSopenharmony_ci        }
55219625d8cSopenharmony_ci    }
55319625d8cSopenharmony_ci
55419625d8cSopenharmony_ci    // Next we verify that only the highest index has takes multiple arguments (if any)
55519625d8cSopenharmony_ci    let only_highest = |a: &Arg| a.is_multiple() && (a.get_index().unwrap_or(0) != highest_idx);
55619625d8cSopenharmony_ci    if cmd.get_positionals().any(only_highest) {
55719625d8cSopenharmony_ci        // First we make sure if there is a positional that allows multiple values
55819625d8cSopenharmony_ci        // the one before it (second to last) has one of these:
55919625d8cSopenharmony_ci        //  * a value terminator
56019625d8cSopenharmony_ci        //  * ArgSettings::Last
56119625d8cSopenharmony_ci        //  * The last arg is Required
56219625d8cSopenharmony_ci
56319625d8cSopenharmony_ci        // We can't pass the closure (it.next()) to the macro directly because each call to
56419625d8cSopenharmony_ci        // find() (iterator, not macro) gets called repeatedly.
56519625d8cSopenharmony_ci        let last = &cmd.get_keymap()[&KeyType::Position(highest_idx)];
56619625d8cSopenharmony_ci        let second_to_last = &cmd.get_keymap()[&KeyType::Position(highest_idx - 1)];
56719625d8cSopenharmony_ci
56819625d8cSopenharmony_ci        // Either the final positional is required
56919625d8cSopenharmony_ci        // Or the second to last has a terminator or .last(true) set
57019625d8cSopenharmony_ci        let ok = last.is_required_set()
57119625d8cSopenharmony_ci            || (second_to_last.terminator.is_some() || second_to_last.is_last_set())
57219625d8cSopenharmony_ci            || last.is_last_set();
57319625d8cSopenharmony_ci        assert!(
57419625d8cSopenharmony_ci            ok,
57519625d8cSopenharmony_ci            "When using a positional argument with `.num_args(1..)` that is *not the \
57619625d8cSopenharmony_ci                 last* positional argument, the last positional argument (i.e. the one \
57719625d8cSopenharmony_ci                 with the highest index) *must* have .required(true) or .last(true) set."
57819625d8cSopenharmony_ci        );
57919625d8cSopenharmony_ci
58019625d8cSopenharmony_ci        // We make sure if the second to last is Multiple the last is ArgSettings::Last
58119625d8cSopenharmony_ci        let ok = second_to_last.is_multiple() || last.is_last_set();
58219625d8cSopenharmony_ci        assert!(
58319625d8cSopenharmony_ci            ok,
58419625d8cSopenharmony_ci            "Only the last positional argument, or second to last positional \
58519625d8cSopenharmony_ci                 argument may be set to `.num_args(1..)`"
58619625d8cSopenharmony_ci        );
58719625d8cSopenharmony_ci
58819625d8cSopenharmony_ci        // Next we check how many have both Multiple and not a specific number of values set
58919625d8cSopenharmony_ci        let count = cmd
59019625d8cSopenharmony_ci            .get_positionals()
59119625d8cSopenharmony_ci            .filter(|p| {
59219625d8cSopenharmony_ci                p.is_multiple_values_set()
59319625d8cSopenharmony_ci                    && !p.get_num_args().expect(INTERNAL_ERROR_MSG).is_fixed()
59419625d8cSopenharmony_ci            })
59519625d8cSopenharmony_ci            .count();
59619625d8cSopenharmony_ci        let ok = count <= 1
59719625d8cSopenharmony_ci            || (last.is_last_set()
59819625d8cSopenharmony_ci                && last.is_multiple()
59919625d8cSopenharmony_ci                && second_to_last.is_multiple()
60019625d8cSopenharmony_ci                && count == 2);
60119625d8cSopenharmony_ci        assert!(
60219625d8cSopenharmony_ci            ok,
60319625d8cSopenharmony_ci            "Only one positional argument with `.num_args(1..)` set is allowed per \
60419625d8cSopenharmony_ci                 command, unless the second one also has .last(true) set"
60519625d8cSopenharmony_ci        );
60619625d8cSopenharmony_ci    }
60719625d8cSopenharmony_ci
60819625d8cSopenharmony_ci    let mut found = false;
60919625d8cSopenharmony_ci
61019625d8cSopenharmony_ci    if cmd.is_allow_missing_positional_set() {
61119625d8cSopenharmony_ci        // Check that if a required positional argument is found, all positions with a lower
61219625d8cSopenharmony_ci        // index are also required.
61319625d8cSopenharmony_ci        let mut foundx2 = false;
61419625d8cSopenharmony_ci
61519625d8cSopenharmony_ci        for p in cmd.get_positionals() {
61619625d8cSopenharmony_ci            if foundx2 && !p.is_required_set() {
61719625d8cSopenharmony_ci                assert!(
61819625d8cSopenharmony_ci                    p.is_required_set(),
61919625d8cSopenharmony_ci                    "Found non-required positional argument with a lower \
62019625d8cSopenharmony_ci                         index than a required positional argument by two or more: {:?} \
62119625d8cSopenharmony_ci                         index {:?}",
62219625d8cSopenharmony_ci                    p.get_id(),
62319625d8cSopenharmony_ci                    p.get_index()
62419625d8cSopenharmony_ci                );
62519625d8cSopenharmony_ci            } else if p.is_required_set() && !p.is_last_set() {
62619625d8cSopenharmony_ci                // Args that .last(true) don't count since they can be required and have
62719625d8cSopenharmony_ci                // positionals with a lower index that aren't required
62819625d8cSopenharmony_ci                // Imagine: prog <req1> [opt1] -- <req2>
62919625d8cSopenharmony_ci                // Both of these are valid invocations:
63019625d8cSopenharmony_ci                //      $ prog r1 -- r2
63119625d8cSopenharmony_ci                //      $ prog r1 o1 -- r2
63219625d8cSopenharmony_ci                if found {
63319625d8cSopenharmony_ci                    foundx2 = true;
63419625d8cSopenharmony_ci                    continue;
63519625d8cSopenharmony_ci                }
63619625d8cSopenharmony_ci                found = true;
63719625d8cSopenharmony_ci                continue;
63819625d8cSopenharmony_ci            } else {
63919625d8cSopenharmony_ci                found = false;
64019625d8cSopenharmony_ci            }
64119625d8cSopenharmony_ci        }
64219625d8cSopenharmony_ci    } else {
64319625d8cSopenharmony_ci        // Check that if a required positional argument is found, all positions with a lower
64419625d8cSopenharmony_ci        // index are also required
64519625d8cSopenharmony_ci        for p in (1..=num_p).rev().filter_map(|n| cmd.get_keymap().get(&n)) {
64619625d8cSopenharmony_ci            if found {
64719625d8cSopenharmony_ci                assert!(
64819625d8cSopenharmony_ci                    p.is_required_set(),
64919625d8cSopenharmony_ci                    "Found non-required positional argument with a lower \
65019625d8cSopenharmony_ci                         index than a required positional argument: {:?} index {:?}",
65119625d8cSopenharmony_ci                    p.get_id(),
65219625d8cSopenharmony_ci                    p.get_index()
65319625d8cSopenharmony_ci                );
65419625d8cSopenharmony_ci            } else if p.is_required_set() && !p.is_last_set() {
65519625d8cSopenharmony_ci                // Args that .last(true) don't count since they can be required and have
65619625d8cSopenharmony_ci                // positionals with a lower index that aren't required
65719625d8cSopenharmony_ci                // Imagine: prog <req1> [opt1] -- <req2>
65819625d8cSopenharmony_ci                // Both of these are valid invocations:
65919625d8cSopenharmony_ci                //      $ prog r1 -- r2
66019625d8cSopenharmony_ci                //      $ prog r1 o1 -- r2
66119625d8cSopenharmony_ci                found = true;
66219625d8cSopenharmony_ci                continue;
66319625d8cSopenharmony_ci            }
66419625d8cSopenharmony_ci        }
66519625d8cSopenharmony_ci    }
66619625d8cSopenharmony_ci    assert!(
66719625d8cSopenharmony_ci        cmd.get_positionals().filter(|p| p.is_last_set()).count() < 2,
66819625d8cSopenharmony_ci        "Only one positional argument may have last(true) set. Found two."
66919625d8cSopenharmony_ci    );
67019625d8cSopenharmony_ci    if cmd
67119625d8cSopenharmony_ci        .get_positionals()
67219625d8cSopenharmony_ci        .any(|p| p.is_last_set() && p.is_required_set())
67319625d8cSopenharmony_ci        && cmd.has_subcommands()
67419625d8cSopenharmony_ci        && !cmd.is_subcommand_negates_reqs_set()
67519625d8cSopenharmony_ci    {
67619625d8cSopenharmony_ci        panic!(
67719625d8cSopenharmony_ci            "Having a required positional argument with .last(true) set *and* child \
67819625d8cSopenharmony_ci                 subcommands without setting SubcommandsNegateReqs isn't compatible."
67919625d8cSopenharmony_ci        );
68019625d8cSopenharmony_ci    }
68119625d8cSopenharmony_ci
68219625d8cSopenharmony_ci    true
68319625d8cSopenharmony_ci}
68419625d8cSopenharmony_ci
68519625d8cSopenharmony_cifn assert_arg(arg: &Arg) {
68619625d8cSopenharmony_ci    debug!("Arg::_debug_asserts:{}", arg.get_id());
68719625d8cSopenharmony_ci
68819625d8cSopenharmony_ci    // Self conflict
68919625d8cSopenharmony_ci    // TODO: this check should be recursive
69019625d8cSopenharmony_ci    assert!(
69119625d8cSopenharmony_ci        !arg.blacklist.iter().any(|x| x == arg.get_id()),
69219625d8cSopenharmony_ci        "Argument '{}' cannot conflict with itself",
69319625d8cSopenharmony_ci        arg.get_id(),
69419625d8cSopenharmony_ci    );
69519625d8cSopenharmony_ci
69619625d8cSopenharmony_ci    assert_eq!(
69719625d8cSopenharmony_ci        arg.get_action().takes_values(),
69819625d8cSopenharmony_ci        arg.is_takes_value_set(),
69919625d8cSopenharmony_ci        "Argument `{}`'s selected action {:?} contradicts `takes_value`",
70019625d8cSopenharmony_ci        arg.get_id(),
70119625d8cSopenharmony_ci        arg.get_action()
70219625d8cSopenharmony_ci    );
70319625d8cSopenharmony_ci    if let Some(action_type_id) = arg.get_action().value_type_id() {
70419625d8cSopenharmony_ci        assert_eq!(
70519625d8cSopenharmony_ci            action_type_id,
70619625d8cSopenharmony_ci            arg.get_value_parser().type_id(),
70719625d8cSopenharmony_ci            "Argument `{}`'s selected action {:?} contradicts `value_parser` ({:?})",
70819625d8cSopenharmony_ci            arg.get_id(),
70919625d8cSopenharmony_ci            arg.get_action(),
71019625d8cSopenharmony_ci            arg.get_value_parser()
71119625d8cSopenharmony_ci        );
71219625d8cSopenharmony_ci    }
71319625d8cSopenharmony_ci
71419625d8cSopenharmony_ci    if arg.get_value_hint() != ValueHint::Unknown {
71519625d8cSopenharmony_ci        assert!(
71619625d8cSopenharmony_ci            arg.is_takes_value_set(),
71719625d8cSopenharmony_ci            "Argument '{}' has value hint but takes no value",
71819625d8cSopenharmony_ci            arg.get_id()
71919625d8cSopenharmony_ci        );
72019625d8cSopenharmony_ci
72119625d8cSopenharmony_ci        if arg.get_value_hint() == ValueHint::CommandWithArguments {
72219625d8cSopenharmony_ci            assert!(
72319625d8cSopenharmony_ci                arg.is_multiple_values_set(),
72419625d8cSopenharmony_ci                "Argument '{}' uses hint CommandWithArguments and must accept multiple values",
72519625d8cSopenharmony_ci                arg.get_id()
72619625d8cSopenharmony_ci            )
72719625d8cSopenharmony_ci        }
72819625d8cSopenharmony_ci    }
72919625d8cSopenharmony_ci
73019625d8cSopenharmony_ci    if arg.index.is_some() {
73119625d8cSopenharmony_ci        assert!(
73219625d8cSopenharmony_ci            arg.is_positional(),
73319625d8cSopenharmony_ci            "Argument '{}' is a positional argument and can't have short or long name versions",
73419625d8cSopenharmony_ci            arg.get_id()
73519625d8cSopenharmony_ci        );
73619625d8cSopenharmony_ci        assert!(
73719625d8cSopenharmony_ci            arg.is_takes_value_set(),
73819625d8cSopenharmony_ci            "Argument '{}` is positional, it must take a value{}",
73919625d8cSopenharmony_ci            arg.get_id(),
74019625d8cSopenharmony_ci            if arg.get_id() == Id::HELP {
74119625d8cSopenharmony_ci                " (`mut_arg` no longer works with implicit `--help`)"
74219625d8cSopenharmony_ci            } else if arg.get_id() == Id::VERSION {
74319625d8cSopenharmony_ci                " (`mut_arg` no longer works with implicit `--version`)"
74419625d8cSopenharmony_ci            } else {
74519625d8cSopenharmony_ci                ""
74619625d8cSopenharmony_ci            }
74719625d8cSopenharmony_ci        );
74819625d8cSopenharmony_ci    }
74919625d8cSopenharmony_ci
75019625d8cSopenharmony_ci    let num_vals = arg.get_num_args().expect(INTERNAL_ERROR_MSG);
75119625d8cSopenharmony_ci    // This can be the cause of later asserts, so put this first
75219625d8cSopenharmony_ci    if num_vals != ValueRange::EMPTY {
75319625d8cSopenharmony_ci        // HACK: Don't check for flags to make the derive easier
75419625d8cSopenharmony_ci        let num_val_names = arg.get_value_names().unwrap_or(&[]).len();
75519625d8cSopenharmony_ci        if num_vals.max_values() < num_val_names {
75619625d8cSopenharmony_ci            panic!(
75719625d8cSopenharmony_ci                "Argument {}: Too many value names ({}) compared to `num_args` ({})",
75819625d8cSopenharmony_ci                arg.get_id(),
75919625d8cSopenharmony_ci                num_val_names,
76019625d8cSopenharmony_ci                num_vals
76119625d8cSopenharmony_ci            );
76219625d8cSopenharmony_ci        }
76319625d8cSopenharmony_ci    }
76419625d8cSopenharmony_ci
76519625d8cSopenharmony_ci    assert_eq!(
76619625d8cSopenharmony_ci        num_vals.takes_values(),
76719625d8cSopenharmony_ci        arg.is_takes_value_set(),
76819625d8cSopenharmony_ci        "Argument {}: mismatch between `num_args` ({}) and `takes_value`",
76919625d8cSopenharmony_ci        arg.get_id(),
77019625d8cSopenharmony_ci        num_vals,
77119625d8cSopenharmony_ci    );
77219625d8cSopenharmony_ci    assert_eq!(
77319625d8cSopenharmony_ci        num_vals.is_multiple(),
77419625d8cSopenharmony_ci        arg.is_multiple_values_set(),
77519625d8cSopenharmony_ci        "Argument {}: mismatch between `num_args` ({}) and `multiple_values`",
77619625d8cSopenharmony_ci        arg.get_id(),
77719625d8cSopenharmony_ci        num_vals,
77819625d8cSopenharmony_ci    );
77919625d8cSopenharmony_ci
78019625d8cSopenharmony_ci    if 1 < num_vals.min_values() {
78119625d8cSopenharmony_ci        assert!(
78219625d8cSopenharmony_ci            !arg.is_require_equals_set(),
78319625d8cSopenharmony_ci            "Argument {}: cannot accept more than 1 arg (num_args={}) with require_equals",
78419625d8cSopenharmony_ci            arg.get_id(),
78519625d8cSopenharmony_ci            num_vals
78619625d8cSopenharmony_ci        );
78719625d8cSopenharmony_ci    }
78819625d8cSopenharmony_ci
78919625d8cSopenharmony_ci    if num_vals == ValueRange::SINGLE {
79019625d8cSopenharmony_ci        assert!(
79119625d8cSopenharmony_ci            !arg.is_multiple_values_set(),
79219625d8cSopenharmony_ci            "Argument {}: mismatch between `num_args` and `multiple_values`",
79319625d8cSopenharmony_ci            arg.get_id()
79419625d8cSopenharmony_ci        );
79519625d8cSopenharmony_ci    }
79619625d8cSopenharmony_ci
79719625d8cSopenharmony_ci    assert_arg_flags(arg);
79819625d8cSopenharmony_ci
79919625d8cSopenharmony_ci    assert_defaults(arg, "default_value", arg.default_vals.iter());
80019625d8cSopenharmony_ci    assert_defaults(
80119625d8cSopenharmony_ci        arg,
80219625d8cSopenharmony_ci        "default_missing_value",
80319625d8cSopenharmony_ci        arg.default_missing_vals.iter(),
80419625d8cSopenharmony_ci    );
80519625d8cSopenharmony_ci    assert_defaults(
80619625d8cSopenharmony_ci        arg,
80719625d8cSopenharmony_ci        "default_value_if",
80819625d8cSopenharmony_ci        arg.default_vals_ifs
80919625d8cSopenharmony_ci            .iter()
81019625d8cSopenharmony_ci            .filter_map(|(_, _, default)| default.as_ref()),
81119625d8cSopenharmony_ci    );
81219625d8cSopenharmony_ci}
81319625d8cSopenharmony_ci
81419625d8cSopenharmony_cifn assert_arg_flags(arg: &Arg) {
81519625d8cSopenharmony_ci    macro_rules! checker {
81619625d8cSopenharmony_ci        ($a:ident requires $($b:ident)|+) => {
81719625d8cSopenharmony_ci            if arg.$a() {
81819625d8cSopenharmony_ci                let mut s = String::new();
81919625d8cSopenharmony_ci
82019625d8cSopenharmony_ci                $(
82119625d8cSopenharmony_ci                    if !arg.$b() {
82219625d8cSopenharmony_ci                        use std::fmt::Write;
82319625d8cSopenharmony_ci                        write!(&mut s, "  Arg::{} is required when Arg::{} is set.\n", std::stringify!($b), std::stringify!($a)).unwrap();
82419625d8cSopenharmony_ci                    }
82519625d8cSopenharmony_ci                )+
82619625d8cSopenharmony_ci
82719625d8cSopenharmony_ci                if !s.is_empty() {
82819625d8cSopenharmony_ci                    panic!("Argument {:?}\n{}", arg.get_id(), s)
82919625d8cSopenharmony_ci                }
83019625d8cSopenharmony_ci            }
83119625d8cSopenharmony_ci        }
83219625d8cSopenharmony_ci    }
83319625d8cSopenharmony_ci
83419625d8cSopenharmony_ci    checker!(is_hide_possible_values_set requires is_takes_value_set);
83519625d8cSopenharmony_ci    checker!(is_allow_hyphen_values_set requires is_takes_value_set);
83619625d8cSopenharmony_ci    checker!(is_allow_negative_numbers_set requires is_takes_value_set);
83719625d8cSopenharmony_ci    checker!(is_require_equals_set requires is_takes_value_set);
83819625d8cSopenharmony_ci    checker!(is_last_set requires is_takes_value_set);
83919625d8cSopenharmony_ci    checker!(is_hide_default_value_set requires is_takes_value_set);
84019625d8cSopenharmony_ci    checker!(is_multiple_values_set requires is_takes_value_set);
84119625d8cSopenharmony_ci    checker!(is_ignore_case_set requires is_takes_value_set);
84219625d8cSopenharmony_ci}
84319625d8cSopenharmony_ci
84419625d8cSopenharmony_cifn assert_defaults<'d>(
84519625d8cSopenharmony_ci    arg: &Arg,
84619625d8cSopenharmony_ci    field: &'static str,
84719625d8cSopenharmony_ci    defaults: impl IntoIterator<Item = &'d OsStr>,
84819625d8cSopenharmony_ci) {
84919625d8cSopenharmony_ci    for default_os in defaults {
85019625d8cSopenharmony_ci        let value_parser = arg.get_value_parser();
85119625d8cSopenharmony_ci        let assert_cmd = Command::new("assert");
85219625d8cSopenharmony_ci        if let Some(delim) = arg.get_value_delimiter() {
85319625d8cSopenharmony_ci            let default_os = RawOsStr::new(default_os);
85419625d8cSopenharmony_ci            for part in default_os.split(delim) {
85519625d8cSopenharmony_ci                if let Err(err) = value_parser.parse_ref(&assert_cmd, Some(arg), &part.to_os_str())
85619625d8cSopenharmony_ci                {
85719625d8cSopenharmony_ci                    panic!(
85819625d8cSopenharmony_ci                        "Argument `{}`'s {}={:?} failed validation: {}",
85919625d8cSopenharmony_ci                        arg.get_id(),
86019625d8cSopenharmony_ci                        field,
86119625d8cSopenharmony_ci                        part.to_str_lossy(),
86219625d8cSopenharmony_ci                        err
86319625d8cSopenharmony_ci                    );
86419625d8cSopenharmony_ci                }
86519625d8cSopenharmony_ci            }
86619625d8cSopenharmony_ci        } else if let Err(err) = value_parser.parse_ref(&assert_cmd, Some(arg), default_os) {
86719625d8cSopenharmony_ci            panic!(
86819625d8cSopenharmony_ci                "Argument `{}`'s {}={:?} failed validation: {}",
86919625d8cSopenharmony_ci                arg.get_id(),
87019625d8cSopenharmony_ci                field,
87119625d8cSopenharmony_ci                default_os,
87219625d8cSopenharmony_ci                err
87319625d8cSopenharmony_ci            );
87419625d8cSopenharmony_ci        }
87519625d8cSopenharmony_ci    }
87619625d8cSopenharmony_ci}
877