summaryrefslogtreecommitdiff
path: root/src/value.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/value.rs')
-rw-r--r--src/value.rs112
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");
+ }
+}