use crate::*; pub struct NamedSwitchQuery<'a> { /// The borrowed switchboard instance. pub switchboard: &'a mut Switchboard, /// Long switch name. pub name: String, /// Short switch name. pub short: Option, /// The default value if the switch has been provided with no value. pub quick: Option, /// Documentation string. pub doc: Option, /// True if this query has already been committed. pub committed: bool, } impl NamedSwitchQuery<'_> { pub fn doc(mut self, doc: &str) -> Self { self.doc = Some(doc.to_string()); self } pub fn short(mut self, short: char) -> Self { if !short.is_ascii_alphanumeric() { fatal!("Invalid short name for argument: {short:?}"); } self.short = Some(short); self } pub fn quick(mut self, value: &str) -> Self { self.quick = Some(value.to_string()); self } pub fn optional(&mut self) { let value = self.get_value(); self.insert(value); } pub fn default(&mut self, default: &str) { match self.get_value() { Some(value) => self.insert(Some(value)), None => self.insert(Some(Some(default.to_string()))), }; } pub fn required(&mut self) { match self.get_value() { Some(value) => self.insert(Some(value)), None => { let error = QueryError::MissingNamed(self.debug_name()); self.switchboard.errors.push(error); } } } fn insert(&mut self, value: Option>) { let queried = QueriedValue { doc: self.doc.clone(), name: self.name.clone(), variant: QueryVariant::Named(self.debug_name()), value, }; if let Some(_) = self.switchboard.values.insert(self.name.clone(), queried) { error!("Duplicate query for name {:?}", self.name.clone()); } self.committed = true; } fn get_value(&mut self) -> Option> { // Find all matches first. let mut matches = Vec::new(); for (i, switch) in self.switchboard.switches.iter().enumerate() { match &switch.0 { SwitchName::Short(other) => if let Some(short) = self.short { if short == *other { matches.push(i) } } SwitchName::Long(other) => if self.name == *other { matches.push(i); }, }; } // Return a value. match matches.len() { 0 => None, 1 => { let found = self.switchboard.switches.remove(matches[0]).1; match found { Some(string) => Some(Some(string)), None => Some(self.quick.clone()), } } _ => { let error = QueryError::Repeated(self.debug_name()); self.switchboard.errors.push(error); None } } } fn debug_name(&self) -> String { let mut debug_name = format!("--{}", self.name); if let Some(short) = self.short { debug_name.push_str(&format!(" (-{})", short)); } debug_name } } impl Drop for NamedSwitchQuery<'_> { fn drop(&mut self) { if !self.committed { self.optional(); } } } pub struct PositionalSwitchQuery<'a> { /// The borrowed switchboard instance. pub switchboard: &'a mut Switchboard, /// The display name of this argument. pub name: String, /// Documentation string. pub doc: Option, /// True if this query has already been committed. pub committed: bool, } impl PositionalSwitchQuery<'_> { pub fn doc(mut self, doc: &str) -> Self { self.doc = Some(doc.to_string()); self } pub fn optional(&mut self) { let value = self.switchboard.pop(); self.insert(value); } pub fn default(&mut self, default: &str) { match self.switchboard.pop() { Some(value) => self.insert(Some(value)), None => self.insert(Some(default.to_string())), }; } pub fn required(&mut self) { match self.switchboard.pop() { Some(value) => self.insert(Some(value)), None => { let error = QueryError::MissingPositional(self.name.clone()); self.switchboard.errors.push(error); } } } fn insert(&mut self, value: Option) { let queried = QueriedValue { doc: self.doc.clone(), name: self.name.clone(), variant: QueryVariant::Positional(self.switchboard.i), value: Some(value), }; if let Some(_) = self.switchboard.values.insert(self.name.clone(), queried) { error!("Duplicate query for name {:?}", self.name.clone()); } self.committed = true; } } impl Drop for PositionalSwitchQuery<'_> { fn drop(&mut self) { if !self.committed { self.optional(); } } }