use std::collections::HashMap;
use crate::{error::Error, errorkind::ErrorKind, opt::Opt, result::Result};
#[derive(Debug, Eq, PartialEq)]
pub struct Parser {
opts: HashMap<char, bool>,
args: Vec<Vec<char>>,
index: usize,
point: usize,
}
impl Parser {
pub fn new(args: &[String], optstring: &str) -> Self {
let optstring: Vec<char> = optstring.chars().collect();
let mut opts = HashMap::new();
let mut i = 0;
let len = optstring.len();
while i < len {
let j = i + 1;
if j < len && optstring[j] == ':' {
opts.insert(optstring[i], true);
i += 1;
} else {
opts.insert(optstring[i], false);
}
i += 1;
}
Self {
opts,
args: args.iter().map(|e| e.chars().collect()).collect(),
index: 1,
point: 0,
}
}
pub fn index(&self) -> usize {
self.index
}
pub fn set_index(&mut self, value: usize) {
self.index = value;
self.point = 0;
}
pub fn incr_index(&mut self) {
self.index += 1;
self.point = 0;
}
}
impl Iterator for Parser {
type Item = Result<Opt>;
fn next(&mut self) -> Option<Result<Opt>> {
if self.point == 0 {
if self.index >= self.args.len()
|| self.args[self.index].is_empty()
|| self.args[self.index][0] != '-'
|| self.args[self.index].len() == 1
{
return None;
}
if self.args[self.index][1] == '-' && self.args[self.index].len() == 2 {
self.incr_index();
return None;
}
self.point += 1;
}
let opt = self.args[self.index][self.point];
self.point += 1;
match self.opts.get(&opt) {
None => {
if self.point >= self.args[self.index].len() {
self.incr_index();
}
Some(Err(Error::new(ErrorKind::UnknownOption, opt)))
},
Some(false) => {
if self.point >= self.args[self.index].len() {
self.incr_index();
}
Some(Ok(Opt(opt, None)))
},
Some(true) => {
let arg: String = if self.point >= self.args[self.index].len() {
self.incr_index();
if self.index >= self.args.len() {
return Some(Err(Error::new(ErrorKind::MissingArgument, opt)));
}
self.args[self.index].iter().collect()
} else {
self.args[self.index]
.clone()
.split_off(self.point)
.iter()
.collect()
};
self.incr_index();
Some(Ok(Opt(opt, Some(arg))))
},
}
}
}