use std::cell::RefCell;
use std::rc::Rc;
use std::boxed::Box;
pub struct Arguments {
args: Vec<Arg>,
operations: Vec<Operation>,
flags: Option<Vec<Flag>>,
}
#[derive(Clone)]
pub struct Operation {
arg: String,
func: Rc<RefCell<Box<dyn Fn(&[Arg], &Arguments) -> ()>>>,
}
impl Operation {
pub fn new<F>(arg: String, func: F) -> Self
where F: Fn(&[Arg], &Arguments),
F: 'static
{
Self {
arg,
func: Rc::new(RefCell::new(Box::new(func))),
}
}
pub fn select(name: &str, ops: &[Operation]) -> Option<Self> {
for op in ops.iter() {
if name == op.arg {
return Some(op.clone());
}
}
None
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Flag {
flag: String,
values: Vec<Arg>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ArgType {
OPTION,
VALUE,
FLAG,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Arg {
name: String,
kind: ArgType,
}
impl Arg {
pub fn new(name: String, kind: ArgType) -> Self {
Self { name, kind }
}
pub fn get_name(&self) -> String {
self.name.clone()
}
}
impl Flag {
pub fn new(flag: String, values: Vec<Arg>) -> Self {
Self { flag, values }
}
pub fn get_name(&self) -> String {
self.flag.clone()
}
pub fn extend_from_slice(&mut self, slice: &[Arg]){
self.values.extend_from_slice(slice);
}
pub fn get_values(&self) -> &[Arg]{
self.values.as_slice()
}
pub fn get_value_vec(&self) -> Vec<Arg>{
self.values.clone()
}
}
impl Arguments {
pub fn new() -> Self {
let mut args: Vec<String> = std::env::args().skip(1).collect();
if args.len() == 0 {
return Self {args: Vec::new(), operations: Vec::new(), flags: None}
}
let mut arglist = Vec::new();
let mut flags = Vec::new();
let option: String = args.remove(0);
let reop = option.clone();
arglist.push(Arg::new(option, ArgType::OPTION));
flags.push(Flag::new(reop, Vec::new()));
for arg in args.iter() {
if arg.find("--").is_some() {
arglist.push(Arg::new(arg.clone(), ArgType::FLAG));
flags.push(Flag::new(arg.clone(), Vec::new()));
} else {
arglist.push(Arg::new(arg.clone(), ArgType::VALUE));
}
}
Self {
args: arglist,
operations: Vec::new(),
flags: Some(flags),
}
}
pub fn invoke_callback<F>(&mut self, flag: &str, func: F)
where F: Fn(&[Arg], &Arguments),
F: 'static
{
self.operations.push(Operation::new(flag.to_string(), func));
}
pub fn parse(&mut self) {
let mut flags_index: Vec<usize> = Vec::new();
flags_index.push(0);
for (index, a) in self.args.iter().enumerate() {
if a.name.find("--").is_some() && index != 0 {
flags_index.push(index);
}
}
let slice_args = self.args.as_slice();
for (ind, flag_index) in flags_index.iter().enumerate() {
let flag = &slice_args[*flag_index];
let start: usize = *flag_index + 1;
let end: usize = match flags_index.get(ind + 1) {
Some(index) => *index,
None => slice_args.len(),
};
let f = self.get_flag_index(&flag.name).expect("flag parsing error");
let slice = self.flags.as_mut().unwrap().as_mut_slice();
slice[f].extend_from_slice(&slice_args[start..end]);
}
for flag in self.flags.as_ref().unwrap().iter(){
if let Some(op) = Operation::select(&flag.get_name(), &self.operations){
let fun = op.func.borrow();
fun(flag.get_values(), &self);
}
}
}
pub fn get_flag(&self, flag_name: &str) -> Option<Flag> {
match &self.flags {
Some(fs) => {
for flag in fs.iter() {
if flag.get_name() == flag_name {
return Some(flag.clone());
} }
None
}
None => None,
}
}
pub fn get_flag_index(&self, flag_name: &str) -> Option<usize>{
match &self.flags {
Some(fs) => {
for (index, flag) in fs.iter().enumerate() {
if flag.get_name() == flag_name {
return Some(index);
}
}
None
}
None => None,
}
}
pub fn get_arg(&self, flag_name: &str) -> Option<Arg> {
for arg in self.args.iter() {
if arg.get_name() == flag_name {
return Some(arg.clone());
}
}
None
}
pub fn has_arg(&self, flag_name: &str) -> bool {
self.get_arg(flag_name).is_some()
}
pub fn get_flags(&self) -> Vec<Arg> {
self.args.clone()
}
}