diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 112 |
1 files changed, 18 insertions, 94 deletions
@@ -1,5 +1,12 @@ mod query; +mod switchboard; +mod value; + pub use query::*; +pub use switchboard::*; +pub use value::*; + +use log::*; pub enum SwitchName { @@ -7,107 +14,24 @@ pub enum SwitchName { Long(String), } - -pub struct Switchboard { - // First positional argument. - pub program: String, - // Positional arguments, stored in reverse order. - pub positional: Vec<String>, - // Named arguments, stored in forward order. - pub switches: Vec<(SwitchName, Option<String>)>, - // All arguments following a '--' token, stored in forward order. - pub unprocessed: Option<Vec<String>>, -} - -impl Switchboard { - pub fn parse(mut args: Vec<String>) -> Self { - let mut positional = Vec::new(); - let mut switches = Vec::new(); - let mut unprocessed = None; - args.reverse(); - - while let Some(arg) = args.pop() { - if arg.is_empty() { - continue; - } else if arg == "--" { - args.reverse(); - unprocessed = Some(args); - break; - } else if let Some(arg) = arg.strip_prefix("--") { - let (name, value) = match arg.split_once("=") { - Some((name, "")) => (name, None), - Some((name, value)) => (name, Some(value.to_string())), - None => (arg, None), - }; - if name.is_empty() { continue } - switches.push((SwitchName::Long(name.to_string()), value)); - } else if let Some(arg) = arg.strip_prefix("-") { - let (name, value) = match arg.split_once("=") { - Some((name, "")) => (name, None), - Some((name, value)) => (name, Some(value.to_string())), - None => (arg, None), - }; - let chars: Vec<char> = name.chars().collect(); - if chars.len() != 1 { continue } - switches.push((SwitchName::Short(chars[0]), value)); - } else { - positional.push(arg) - } - } - // Reverse order of positional arguments and move program name. - positional.reverse(); - let program = positional.pop().unwrap(); - Self { - program, positional, switches, unprocessed, - } - } - - pub fn from_env() -> Self { - let mut args = Vec::new(); - for arg_os in std::env::args_os() { - args.push(arg_os.to_string_lossy().to_string()); - } - Self::parse(args) - } - - pub fn named(&mut self, name: &str) -> NamedSwitchQuery { - validate_name(name); - NamedSwitchQuery { - switchboard: self, - name: name.to_string(), - short: None, - default: None, - quick: None, - } - } - - pub fn positional(&mut self, name: &str) -> PositionalSwitchQuery { - validate_name(name); - PositionalSwitchQuery { - switchboard: self, - name: name.to_string(), - default: None, +impl std::fmt::Display for SwitchName { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + SwitchName::Short(c) => write!(f, "-{c}"), + SwitchName::Long(s) => write!(f, "--{s}"), } } - - /// Check the next positional argument without consuming it. - pub fn peek(&self) -> Option<&str> { - self.positional.last().map(|p| p.as_str()) - } - - /// Consume the next positional argument. - pub fn pop(&mut self) { - self.positional.pop(); - } } - -pub enum SwitchboardError { +pub enum QueryError { + MissingNamed(String), + MissingPositional(String), + // String is the debug name of the switch + Repeated(String), } - fn validate_name(name: &str) { if !name.chars().all(|c| c.is_ascii_lowercase() || c.is_digit(10) || c == '-') { - panic!("Invalid name for argument: {name:?}"); + log::fatal!("Invalid name for argument: {name:?}"); } } |