use std::io;
use std::collections::HashMap;
#[macro_export]
macro_rules! parse {
($args: expr, $arglen: expr, $parser: expr) => {
let args: Vec<String> = $args;
let arglen: u8 = $arglen;
$parser.parse(args, arglen).unwrap();
}
}
#[macro_export]
macro_rules! register {
($flag: expr, $description: expr, $func: expr, $parser: expr) => {
let function = $func;
let flag: &str = $flag;
let desc: &str = $description;
$parser.register(flag, desc, function);
}
}
pub struct Func<'a> {
pub func_closure: Box<dyn Fn(String) + 'a>,
pub func_description: String
}
impl <'a>Func<'a> {
pub fn new(func: Box<dyn Fn(String) + 'a>, desc: String) -> Func<'a> {
Func {
func_closure: func,
func_description: desc
}
}
}
pub struct Parser<'a> {
pub argmap: HashMap<String, Func<'a>>,
pub description: String
}
impl <'a>Parser<'a> {
pub fn new(desc: &str) -> Parser<'a> {
Parser {
argmap: HashMap::new(),
description: String::from(desc)
}
}
pub fn register<F: Fn(String) + 'a>(&mut self, flag: &str, desc: &str, func: F) {
self.argmap.insert(String::from(flag), Func::new(Box::new(func), String::from(desc)));
}
fn execute<F>(&self, arg: String, f: F) where F: Fn(String) {
f(arg);
}
pub fn parse(&self, args: Vec<String>, arglen: u8) -> Result<(), io::Error>{
if (arglen-1)%2 != 0 { eprintln!("[ERROR] Invalid argument length: {}\n[ERROR] Exiting...", arglen-1);
std::process::exit(0x0100); }
for x in (1..arglen).step_by(2) {
let flag: String;
flag = args[x as usize].to_owned();
let arg: String;
arg = args[(x+1) as usize].to_owned();
let function = &self.resolve_func(flag.clone()).unwrap().func_closure;
self.execute(arg, function); }
Ok(())
}
fn resolve_func(&self, flag: String) -> Result<&Func<'a>, ()>{
match self.argmap.get(&flag) {
Some(func) => Ok(func),
None => {
eprintln!("[ERROR] Unknown argument flag: {}\n[ERROR] Exiting...\n", flag);
std::process::exit(0x0100);
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
fn test(_arg: String) {
println!("test")
}
#[test]
fn test_parsing() {
let mut parser: Parser = Parser::new("test");
register!("-test", "test", test, parser);
let args: Vec<String> = vec![String::from("binary"), String::from("-test"), String::from("test")];
parse!(args.clone(), args.len() as u8, parser);
}
}