diff options
Diffstat (limited to 'src/value.rs')
-rw-r--r-- | src/value.rs | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/src/value.rs b/src/value.rs new file mode 100644 index 0000000..99468fa --- /dev/null +++ b/src/value.rs @@ -0,0 +1,112 @@ +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<String>, + pub name: String, + pub variant: QueryVariant, + /// Some if switch passed, then some if value passed. + pub value: Option<Option<String>>, +} + +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<PathBuf> { + 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<String> { + 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"); + } +} |