summaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
authorBen Bridle <ben@derelict.engineering>2025-03-03 20:51:01 +1300
committerBen Bridle <ben@derelict.engineering>2025-03-03 20:54:45 +1300
commit8a43a02b6950455aedbbdbee737bee1654aa91ef (patch)
tree64e31ff1cfbbdce22e104adcb1ad81f051019ca1 /src/lib.rs
parentea70fa89659e5cf1a9d4ca6ea31fb67f7a2cc633 (diff)
downloadswitchboard-8a43a02b6950455aedbbdbee737bee1654aa91ef.zip
Implement error reporting
The library has been redesigned so that all queries can be entered before any values are parsed. This allows all errors unrelated to value parsing to be displayed as a batch.
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs112
1 files changed, 18 insertions, 94 deletions
diff --git a/src/lib.rs b/src/lib.rs
index e25725d..d968cf2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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:?}");
}
}