Add u16 argument type
This commit is contained in:
parent
b61bf1f827
commit
3e97fee691
|
@ -2,7 +2,7 @@
|
|||
name = "switches"
|
||||
version = "1.0.0"
|
||||
authors = ["Ben Bridle <bridle.benjamin@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
|
46
src/lib.rs
46
src/lib.rs
|
@ -1,2 +1,46 @@
|
|||
mod switches;
|
||||
pub use switches::Switches;
|
||||
pub use switches::{Switches, SwitchesError as Error};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! generate {
|
||||
(
|
||||
$structname:ident {
|
||||
$($field:ident: $type:tt ($($opt:expr),+)),* $(,)?
|
||||
}
|
||||
) => {
|
||||
macro_rules! build {
|
||||
($f:ident, PathBuf) => {$f.as_path()};
|
||||
($f:ident, Option<PathBuf>) => {$f.as_opt_path()};
|
||||
($f:ident, String) => {$f.as_string()};
|
||||
($f:ident, Option<String>) => {$f.as_opt_string()};
|
||||
($f:ident, bool) => {$f.as_flag()};
|
||||
($f:ident, u16) => {$f.as_u16()};
|
||||
}
|
||||
|
||||
pub struct $structname {
|
||||
$(pub $field: $type),*
|
||||
}
|
||||
impl $structname {
|
||||
pub fn parse() -> Result<Self, switches::Error> {
|
||||
let mut switches = switches::Switches::from_env();
|
||||
$(
|
||||
let mut $field = switches$(.or($opt))+;
|
||||
let $field = build!($field, $type)?;
|
||||
)*
|
||||
Ok(Self {
|
||||
$($field,)*
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_and_raise() -> Self {
|
||||
match Self::parse() {
|
||||
Ok(parsed) => parsed,
|
||||
Err(err) => {
|
||||
eprintln!("[ERROR] {}", err);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
switches::generate! {
|
||||
Args {
|
||||
source_folder: PathBuf ("-f", "--folder"),
|
||||
name: String ("-n", "--name"),
|
||||
delete: bool ("--delete"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let args = Args::parse_and_raise();
|
||||
println!(" Folder: {:?}", args.source_folder);
|
||||
println!(" Name: {:?}", args.name);
|
||||
println!(" Delete: {:?}", args.delete);
|
||||
}
|
135
src/switches.rs
135
src/switches.rs
|
@ -1,3 +1,14 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
macro_rules! return_none {
|
||||
($x:expr) => {
|
||||
match $x {
|
||||
Some(v) => v,
|
||||
None => return Ok(None),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Switches {
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
@ -11,24 +22,20 @@ impl Switches {
|
|||
}
|
||||
|
||||
pub fn get(&mut self, switch: &str) -> SwitchBuilder {
|
||||
let builder = SwitchBuilder::new(&mut self.args);
|
||||
builder.or(switch)
|
||||
SwitchBuilder::new(&mut self.args).or(switch)
|
||||
}
|
||||
|
||||
pub fn check_for_unused_arguments(&mut self) -> Result<(), Error> {
|
||||
if self.args.len() > 0 {
|
||||
Err(Error::UnexpectedArguments(self.args.clone()))
|
||||
pub fn or(&mut self, switch: &str) -> SwitchBuilder {
|
||||
self.get(switch)
|
||||
}
|
||||
|
||||
pub fn check_for_unused_arguments(&mut self) -> Result<(), SwitchesError> {
|
||||
if !self.args.is_empty() {
|
||||
Err(SwitchesError::UnexpectedArguments(self.args.clone()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value(&mut self) -> Option<String> {
|
||||
if self.args.is_empty() {
|
||||
return None;
|
||||
};
|
||||
Some(self.args.remove(0))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SwitchBuilder<'a> {
|
||||
|
@ -39,7 +46,7 @@ pub struct SwitchBuilder<'a> {
|
|||
}
|
||||
|
||||
impl<'a> SwitchBuilder<'a> {
|
||||
pub fn new(args: &'a mut Vec<String>) -> Self {
|
||||
fn new(args: &'a mut Vec<String>) -> Self {
|
||||
Self {
|
||||
args,
|
||||
matched_indices: Vec::new(),
|
||||
|
@ -56,24 +63,30 @@ impl<'a> SwitchBuilder<'a> {
|
|||
self.matched_switches.push(arg.to_string());
|
||||
}
|
||||
}
|
||||
return self;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn as_flag(mut self) -> Result<bool, Error> {
|
||||
pub fn as_flag(&mut self) -> Result<bool, SwitchesError> {
|
||||
let result = match self.matched_indices.len() {
|
||||
0 => Ok(false),
|
||||
1 => Ok(true),
|
||||
_ => Err(Error::MultipleMatchesFound(self.matched_switches.clone())),
|
||||
_ => Err(SwitchesError::MultipleMatchesFound(
|
||||
self.matched_switches.clone(),
|
||||
)),
|
||||
};
|
||||
self.remove_matches();
|
||||
return result;
|
||||
result
|
||||
}
|
||||
|
||||
pub fn as_opt_string(&mut self) -> Result<Option<String>, Error> {
|
||||
pub fn as_opt_string(&mut self) -> Result<Option<String>, SwitchesError> {
|
||||
let switch_index = match self.matched_indices.len() {
|
||||
0 => return Ok(None),
|
||||
1 => self.matched_indices[0],
|
||||
_ => return Err(Error::MultipleMatchesFound(self.matched_switches.clone())),
|
||||
_ => {
|
||||
return Err(SwitchesError::MultipleMatchesFound(
|
||||
self.matched_switches.clone(),
|
||||
))
|
||||
}
|
||||
};
|
||||
let switch = self.matched_switches[0].clone();
|
||||
let value_index = switch_index + 1;
|
||||
|
@ -82,19 +95,48 @@ impl<'a> SwitchBuilder<'a> {
|
|||
self.matched_indices.push(value_index);
|
||||
value.to_string()
|
||||
}
|
||||
None => return Err(Error::NoValueForSwitch(switch)),
|
||||
None => return Err(SwitchesError::NoValueForSwitch(switch)),
|
||||
};
|
||||
if value.starts_with("-") {
|
||||
return Err(Error::NoValueForSwitch(switch));
|
||||
if value.starts_with('-') {
|
||||
return Err(SwitchesError::NoValueForSwitch(switch));
|
||||
};
|
||||
self.remove_matches();
|
||||
return Ok(Some(value));
|
||||
Ok(Some(value))
|
||||
}
|
||||
|
||||
pub fn as_string(&mut self) -> Result<String, Error> {
|
||||
match self.as_opt_string()? {
|
||||
pub fn as_opt_path(&mut self) -> Result<Option<PathBuf>, SwitchesError> {
|
||||
let string = return_none!(self.as_opt_string()?);
|
||||
let mut path = std::env::current_dir().unwrap();
|
||||
path.push(PathBuf::from(string));
|
||||
Ok(Some(path))
|
||||
}
|
||||
|
||||
pub fn as_opt_u16(&mut self) -> Result<Option<u16>, SwitchesError> {
|
||||
let string = return_none!(self.as_opt_string()?);
|
||||
let int = string.parse().unwrap();
|
||||
Ok(Some(int))
|
||||
}
|
||||
|
||||
pub fn as_string(&mut self) -> Result<String, SwitchesError> {
|
||||
let string = self.as_opt_string();
|
||||
self.make_mandatory(string)
|
||||
}
|
||||
pub fn as_path(&mut self) -> Result<PathBuf, SwitchesError> {
|
||||
let path = self.as_opt_path();
|
||||
self.make_mandatory(path)
|
||||
}
|
||||
pub fn as_u16(&mut self) -> Result<u16, SwitchesError> {
|
||||
let int = self.as_opt_u16();
|
||||
self.make_mandatory(int)
|
||||
}
|
||||
|
||||
fn make_mandatory<T>(
|
||||
&mut self,
|
||||
result: Result<Option<T>, SwitchesError>,
|
||||
) -> Result<T, SwitchesError> {
|
||||
match result? {
|
||||
Some(value) => Ok(value),
|
||||
None => Err(Error::NoMatchFound(self.all_switches.clone())),
|
||||
None => Err(SwitchesError::NoMatchFound(self.all_switches.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,9 +147,40 @@ impl<'a> SwitchBuilder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum Error {
|
||||
MultipleMatchesFound(Vec<String>), // All of the switches that were matched
|
||||
NoMatchFound(Vec<String>), // All of the switches that were looked for
|
||||
NoValueForSwitch(String), //
|
||||
UnexpectedArguments(Vec<String>),
|
||||
fn join(vec: &[String]) -> String {
|
||||
let mut output = String::new();
|
||||
for (i, string) in vec.iter().enumerate() {
|
||||
match i == vec.len() - 1 {
|
||||
true => output.push_str(&format!("'{}'", string)),
|
||||
false => output.push_str(&format!("'{}', ", string)),
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
pub enum SwitchesError {
|
||||
MultipleMatchesFound(Vec<String>), // contains all of the switches that were matched
|
||||
NoMatchFound(Vec<String>), // contains all of the switches that were looked for
|
||||
NoValueForSwitch(String),
|
||||
UnexpectedArguments(Vec<String>),
|
||||
InvalidValue(String, String, String),
|
||||
}
|
||||
impl std::fmt::Display for SwitchesError {
|
||||
#[rustfmt::skip]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
let string = match self {
|
||||
SwitchesError::MultipleMatchesFound(matches) => {
|
||||
format!("Multiple conflicting arguments were provided: {}", join(matches))}
|
||||
SwitchesError::NoMatchFound(switches) => {
|
||||
format!("One of these arguments must be provided: {}", join(switches))}
|
||||
SwitchesError::NoValueForSwitch(switch) => {
|
||||
format!("This argument needs to be followed by a value: '{}'", switch)}
|
||||
SwitchesError::UnexpectedArguments(args) => {
|
||||
format!("Unexpected arguments were provided: {}", join(args))}
|
||||
SwitchesError::InvalidValue(value, arg, ty) => {
|
||||
format!("A non-{} value was passed to '{}': {}", ty, arg, value)}
|
||||
|
||||
};
|
||||
write!(f, "{}", string)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue