args_functional/
lib.rs

1//for every flag there will be child arguments
2use std::cell::RefCell;
3use std::rc::Rc;
4use std::boxed::Box;
5
6pub struct Arguments {
7    args: Vec<Arg>,
8    operations: Vec<Operation>,
9    flags: Option<Vec<Flag>>,
10    //callback: Option<Vec<&'static Fn(Option<&Vec<Flag>>) -> ()>>,
11}
12#[derive(Clone)]
13pub struct Operation {
14    arg: String,
15    func: Rc<RefCell<Box<dyn Fn(&[Arg], &Arguments) -> ()>>>,
16}
17///associates a given flag with a callback method
18impl Operation {
19    pub fn new<F>(arg: String, func: F) -> Self 
20        where F: Fn(&[Arg], &Arguments),
21            F: 'static
22    {
23        Self {
24            arg,
25            func: Rc::new(RefCell::new(Box::new(func))),
26        }
27    }
28    pub fn select(name: &str, ops: &[Operation]) -> Option<Self> {
29        for op in ops.iter() {
30            if name == op.arg {
31                return Some(op.clone());
32            }
33        }
34        None
35    }
36}
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct Flag {
39    flag: String,
40    values: Vec<Arg>,
41}
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub enum ArgType {
44    OPTION,
45    VALUE,
46    FLAG,
47}
48///holds all arguments, allowing them to be sorted into types aka flag, value, option where values are children of flags
49#[derive(Debug, Clone, PartialEq, Eq)]
50pub struct Arg {
51    name: String,
52    kind: ArgType,
53}
54
55impl Arg {
56    pub fn new(name: String, kind: ArgType) -> Self {
57        Self { name, kind }
58    }
59    pub fn get_name(&self) -> String {
60        self.name.clone()
61    }
62}
63///flag as something containing --
64impl Flag {
65    pub fn new(flag: String, values: Vec<Arg>) -> Self {
66        Self { flag, values }
67    }
68    pub fn get_name(&self) -> String {
69        self.flag.clone()
70    }
71    pub fn extend_from_slice(&mut self, slice: &[Arg]){
72        self.values.extend_from_slice(slice);
73    }
74    pub fn get_values(&self) -> &[Arg]{
75        self.values.as_slice()
76    }
77    pub fn get_value_vec(&self) -> Vec<Arg>{
78        self.values.clone()
79    }
80}
81//let fun = op.func.get_mut();
82//fun(&slice_args[start..end], &self);
83///main struct that organizes argument parsing
84impl Arguments {
85    ///constructs the parser
86    pub fn new() -> Self {
87        let mut args: Vec<String> = std::env::args().skip(1).collect();
88        if args.len() == 0 {
89            return Self {args: Vec::new(), operations: Vec::new(), flags: None}
90        }
91        let mut arglist = Vec::new();
92        let mut flags = Vec::new();
93        let option: String = args.remove(0);
94        let reop = option.clone();
95        arglist.push(Arg::new(option, ArgType::OPTION));
96        flags.push(Flag::new(reop, Vec::new()));
97        for arg in args.iter() {
98            if arg.find("--").is_some() {
99                arglist.push(Arg::new(arg.clone(), ArgType::FLAG));
100                flags.push(Flag::new(arg.clone(), Vec::new()));
101            } else {
102                arglist.push(Arg::new(arg.clone(), ArgType::VALUE));
103            }
104        }
105        Self {
106            args: arglist,
107            operations: Vec::new(),
108            flags: Some(flags),
109        }
110    }
111    ///adds a callback for a flag when it is found
112    pub fn invoke_callback<F>(&mut self, flag: &str, func: F)
113        where F: Fn(&[Arg], &Arguments),
114            F: 'static
115    {
116        self.operations.push(Operation::new(flag.to_string(), func));
117    }
118    ///invokes methods associated with the flags saved above
119    pub fn parse(&mut self) {
120        //seperate out flags and their children
121        //then iterate through again to invoke each operation
122        // convert args to slice so direct access is safer
123        let mut flags_index: Vec<usize> = Vec::new();
124        flags_index.push(0);
125        for (index, a) in self.args.iter().enumerate() {
126            if a.name.find("--").is_some() && index != 0 {
127                flags_index.push(index);
128            }
129        }
130        let slice_args = self.args.as_slice();
131        for (ind, flag_index) in flags_index.iter().enumerate() {
132            let flag = &slice_args[*flag_index];
133                let start: usize = *flag_index + 1;
134                let end: usize = match flags_index.get(ind + 1) {
135                    Some(index) => *index,
136                    None => slice_args.len(),
137                };
138                let f = self.get_flag_index(&flag.name).expect("flag parsing error");
139                let slice = self.flags.as_mut().unwrap().as_mut_slice();
140                slice[f].extend_from_slice(&slice_args[start..end]);
141                
142        }
143        for flag in self.flags.as_ref().unwrap().iter(){
144            if let Some(op) = Operation::select(&flag.get_name(), &self.operations){
145                let fun = op.func.borrow();
146                fun(flag.get_values(), &self);
147            }
148        }
149    }
150    ///this function is broken for now
151    pub fn get_flag(&self, flag_name: &str) -> Option<Flag> {
152        match &self.flags {
153            Some(fs) => {
154                for flag in fs.iter() {
155                    if flag.get_name() == flag_name {
156                        return Some(flag.clone());
157                    }                }
158                None
159            }
160            None => None,
161        }
162    }
163    pub fn get_flag_index(&self, flag_name: &str) -> Option<usize>{
164        match &self.flags {
165            Some(fs) => {
166                for (index, flag) in fs.iter().enumerate() {
167                    if flag.get_name() == flag_name {
168                        return Some(index);
169                    }
170                }
171                None
172            }
173            None => None,
174        }
175    }
176    ///this allows a callback to get a specific argument or flag
177    pub fn get_arg(&self, flag_name: &str) -> Option<Arg> {
178        for arg in self.args.iter() {
179            if arg.get_name() == flag_name {
180                return Some(arg.clone());
181            }
182        }
183        None
184    }
185    ///checks if a flag exists at the same level as a registered operation
186    pub fn has_arg(&self, flag_name: &str) -> bool {
187        self.get_arg(flag_name).is_some()
188    }
189    pub fn get_flags(&self) -> Vec<Arg> {
190        self.args.clone()
191    }
192}