pub const NUM_VALUES: usize = 16;
pub type Values<'a> = [&'a str; NUM_VALUES];
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum NumArgs {
None,
All,
Number(u32)
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum ArgName<'a> {
Name(&'a str),
Flag(&'a str)
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Arg<'a> {
name: ArgName<'a>,
num_args: NumArgs,
matched_data: Values<'a>
}
pub fn args<'a>(a: &[&'a str]) -> Values<'a> {
let mut result = [""; NUM_VALUES];
for (i, arg) in a.clone().iter().enumerate() {
result[i] = arg.clone();
}
result
}
fn to_argname<'a>(name: &'a str) -> ArgName<'a> {
if let Some(ch) = name.chars().nth(0) {
match ch {
'-' => {
ArgName::Flag(name)
},
_ => {
ArgName::Name(name)
}
}
} else {
ArgName::Name(name)
}
}
impl<'a> Arg<'a> {
pub fn new(name: &'a str) -> Self {
Self {
name: to_argname(name),
num_args: NumArgs::Number(1),
matched_data: [""; NUM_VALUES]
}
}
pub fn has_name(&self, name: &'a str) -> bool {
to_argname(name) == self.name
}
pub fn is_flag(&self) -> bool {
match self.name {
ArgName::Name(_) => false,
ArgName::Flag(_) => true
}
}
pub fn num_values(mut self, n: i32) -> Self {
if let ArgName::Flag(_) = self.name {
self.num_args = match n {
-1 => NumArgs::All,
0 => NumArgs::None,
n => NumArgs::Number(n as u32),
};
}
self
}
pub fn get_values(&self) -> Values<'a> {
self.matched_data
}
pub fn is_match(&self, slice_matches: &[&'a str]) -> bool {
if self.has_name("") { return false; }
let matches = args(slice_matches);
if self.matched_data[0] != "" { return false; }
let mut num_args = 0;
for m in matches.iter() {
if m.clone() != "" { num_args += 1; }
}
match self.name {
ArgName::Name(_) => {
let valid_num_args = match self.num_args {
NumArgs::Number(1) => num_args == 1,
NumArgs::All | NumArgs::Number(_) | NumArgs::None => false,
};
valid_num_args
},
ArgName::Flag(n) => {
let valid_num_args = match self.num_args {
NumArgs::None => num_args == 1,
NumArgs::All => true,
NumArgs::Number(n) => num_args == n + 1
};
valid_num_args && (matches[0] == n)
}
}
}
pub fn consume<'b>(&mut self, values: &'b mut Values<'a>) -> bool {
let mut matched_up_to = 0;
let mut consumed = false;
for n in (1..values.len()).rev() {
if (*values)[n-1] == "" {
continue;
}
if self.is_match(&values[0..n]) {
if self.is_flag() {
self.matched_data = args(&values[1..n]);
} else {
self.matched_data = args(&values[0..n]);
}
matched_up_to = n;
consumed = true;
}
}
*values = args(&values[matched_up_to..]);
consumed
}
}