diff options
author | pommicket <pommicket@gmail.com> | 2025-08-29 04:25:57 -0400 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2025-08-29 04:25:57 -0400 |
commit | af16284921b65f92601279001531862d1c80cee7 (patch) | |
tree | ffabe5598ab96839de4ff44c53fa2ef44f4db062 /src/argparse.rs |
Initial commit (v. 0.1.0)v0.1.0
Diffstat (limited to 'src/argparse.rs')
-rw-r--r-- | src/argparse.rs | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/src/argparse.rs b/src/argparse.rs new file mode 100644 index 0000000..8fd6ae5 --- /dev/null +++ b/src/argparse.rs @@ -0,0 +1,82 @@ +use std::collections::{HashMap, HashSet}; +use std::fmt::Debug; +use std::hash::Hash; + +#[derive(Debug)] +pub struct Args<Flag, Param> { + flags: HashSet<Flag>, + params: HashMap<Param, String>, + lone_args: Vec<String>, +} + +impl<Flag: Hash + Eq, Param: Hash + Eq> Args<Flag, Param> { + pub fn is_set(&self, flag: Flag) -> bool { + self.flags.contains(&flag) + } + pub fn get(&self, param: Param) -> Option<&str> { + Some(self.params.get(¶m)?.as_ref()) + } + pub fn lone_args(&self) -> impl '_ + Iterator<Item = &str> { + self.lone_args.iter().map(|x| x.as_ref()) + } + pub fn lone_args_count(&self) -> usize { + self.lone_args.len() + } +} + +pub fn parse_args<Flag: Copy + Hash + Eq + Debug, Param: Copy + Hash + Eq + Debug>( + flag_names: &HashMap<&str, Flag>, + param_names: &HashMap<&str, Param>, +) -> Result<Args<Flag, Param>, String> { + let mut arg_iter = std::env::args_os(); + arg_iter.next(); // program name + let mut args = Args { + flags: HashSet::new(), + params: HashMap::new(), + lone_args: vec![], + }; + let mut double_dash = false; + let mut param: Option<(String, Param)> = None; + assert!(flag_names.keys().all(|x| x.starts_with('-'))); + assert!(param_names.keys().all(|x| x.starts_with('-'))); + for arg in arg_iter { + let arg = arg + .into_string() + .map_err(|arg| format!("Argument includes bad UTF-8: {arg:?}"))?; + if let Some((_name, p)) = param.as_ref() { + args.params.insert(*p, arg); + param = None; + continue; + } + if double_dash { + args.lone_args.push(arg); + continue; + } + if arg == "--" { + double_dash = true; + continue; + } + if let Some(flag) = flag_names.get(arg.as_str()) { + args.flags.insert(*flag); + continue; + } + if let Some(p) = param_names.get(arg.as_str()) { + param = Some((arg, *p)); + continue; + } + if let Some((p, value)) = arg.split_once('=') + && let Some(p) = param_names.get(p) + { + args.params.insert(*p, value.into()); + continue; + } + if arg.starts_with('-') { + return Err(format!("Unrecognized option: {arg}")); + } + args.lone_args.push(arg); + } + if let Some((name, _p)) = param { + return Err(format!("No argument provided to {name}")); + } + Ok(args) +} |