use crate::*; use std::path::PathBuf; macro_rules! as_number { ($type:ty, $name:expr, $error:ty) => { paste::paste! { pub fn [< as_ $type >](&mut self) -> $type { self.[< as_ $type _opt >]().unwrap_or_else(|| self.missing("number")) } pub fn [< as_ $type _opt>](&mut self) -> Option<$type> { self.value().as_ref().map(|v| v.trim().parse().unwrap_or_else( |e: $error| self.error(&v, $name, e.to_string()))) } } }; } pub struct QueriedValue { pub doc: Option, pub name: String, pub variant: QueryVariant, /// Some if switch passed, then some if value passed. pub value: Option>, } pub enum QueryVariant { Positional(usize), Named(String), } impl QueriedValue { pub fn value(&self) -> Option<&String> { match &self.value { Some(value) => value.as_ref(), None => None, } } pub fn as_bool(self) -> bool { if let Some(value) = self.value { if let Some(value) = value { match value.to_lowercase().as_str() { "y"|"yes"|"t"|"true" => true, "n"|"no" |"f"|"false" => false, _ => true, } } else { true } } else { false } } pub fn as_path(&mut self) -> PathBuf { self.as_path_opt().unwrap_or_else(|| self.missing("path")) } pub fn as_path_opt(&mut self) -> Option { if let Some(value) = self.value() { if !value.is_empty() { return Some(PathBuf::from(value)); } } return None; } pub fn as_string(&mut self) -> String { self.as_string_opt().unwrap_or_else(|| self.missing("string")) } pub fn as_string_opt(&mut self) -> Option { self.value().cloned() } as_number!{ f32, "f32" , std::num::ParseFloatError } as_number!{ f64, "f64" , std::num::ParseFloatError } as_number!{ u8, "u8" , std::num::ParseIntError } as_number!{ u16, "u16" , std::num::ParseIntError } as_number!{ u32, "u32" , std::num::ParseIntError } as_number!{ u64, "u64" , std::num::ParseIntError } as_number!{ usize, "usize", std::num::ParseIntError } as_number!{ i8, "i8" , std::num::ParseIntError } as_number!{ i16, "i16" , std::num::ParseIntError } as_number!{ i32, "i32" , std::num::ParseIntError } as_number!{ i64, "i64" , std::num::ParseIntError } as_number!{ isize, "isize", std::num::ParseIntError } fn locator(&self) -> String { match &self.variant { QueryVariant::Positional(_) => { let name = &self.name; format!("<{name}> argument") } QueryVariant::Named(name) => { format!("{name} switch") } } } fn error(&self, value: &str, ty: &str, err: String) -> ! { let locator = self.locator(); fatal!("The value {value:?} passed to the {locator} could not be parsed as a {ty}: {err}"); } fn missing(&self, _ty: &str) -> ! { let locator = self.locator(); fatal!("The {locator} is required"); } }