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