supplement 0.2.3

The awesome supplement for your awesome CLI app
Documentation
use crate::core::Arg;

pub(crate) struct ArgsContext<'a, ID> {
    args: &'a [Arg<ID>],
    cur_arg_values_count: usize,
    start_idx: usize,
}
impl<'a, ID> ArgsContext<'a, ID> {
    pub fn new(args: &'a [Arg<ID>]) -> Self {
        Self {
            args,
            start_idx: 0,
            cur_arg_values_count: 0,
        }
    }
    pub fn has_seen_arg(&self) -> bool {
        self.start_idx != 0 || self.cur_arg_values_count != 0
    }
    pub fn next_arg(&mut self) -> Option<&Arg<ID>> {
        log::debug!("next arg called");
        let args = &self.args[self.start_idx..];
        let next = args.iter().next()?;
        if next.max_values == self.cur_arg_values_count + 1 {
            self.start_idx += 1;
            self.cur_arg_values_count = 0;
        } else {
            self.cur_arg_values_count += 1;
        }

        Some(next)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::core::CowOwned;
    use crate::id;

    const ARG1: Arg<u32> = Arg {
        id: Some(line!()),
        seen_id: id::SingleVal::new(line!()).into(),
        max_values: 1,
        possible_values: CowOwned::Borrow(&[]),
    };
    const ARG2: Arg<u32> = Arg {
        id: Some(line!()),
        seen_id: id::SingleVal::new(line!()).into(),
        max_values: 1,
        possible_values: CowOwned::Borrow(&[]),
    };
    #[test]
    fn test_empty_arg_ctx() {
        let mut ctx = ArgsContext::<u32>::new(&[]);
        assert!(!ctx.has_seen_arg());
        assert!(ctx.next_arg().is_none());
        assert!(!ctx.has_seen_arg());
    }
    #[test]
    fn test_simple_arg_ctx() {
        let mut ctx = ArgsContext::new(const { &[ARG1, ARG2] });
        assert!(!ctx.has_seen_arg());
        assert_eq!(ctx.next_arg().unwrap().id, ARG1.id);
        assert!(ctx.has_seen_arg());
        assert_eq!(ctx.next_arg().unwrap().id, ARG2.id);
        assert!(ctx.next_arg().is_none());
    }

    const ARG3: Arg<u32> = Arg {
        id: Some(line!()),
        seen_id: id::MultiVal::new(line!()).into(),
        max_values: 2,
        possible_values: CowOwned::Borrow(&[]),
    };
    const ARG4: Arg<u32> = Arg {
        id: Some(line!()),
        seen_id: id::MultiVal::new(line!()).into(),
        max_values: 3,
        possible_values: CowOwned::Borrow(&[]),
    };
    #[test]
    fn test_var_arg_ctx() {
        let mut ctx = ArgsContext::new(const { &[ARG1, ARG3, ARG4] });
        assert!(!ctx.has_seen_arg());
        assert_eq!(ctx.next_arg().unwrap().id, ARG1.id);
        assert!(ctx.has_seen_arg());

        assert_eq!(ctx.next_arg().unwrap().id, ARG3.id);
        assert_eq!(ctx.next_arg().unwrap().id, ARG3.id);

        assert_eq!(ctx.next_arg().unwrap().id, ARG4.id);
        assert_eq!(ctx.next_arg().unwrap().id, ARG4.id);
        assert_eq!(ctx.next_arg().unwrap().id, ARG4.id);

        assert!(ctx.next_arg().is_none());
    }
}