aopt 1.4.3

A flexible and typed getopt tools
Documentation
use std::fmt::Debug;
use std::marker::PhantomData;

use super::MatchPolicy;

use crate::opt::Opt;
use crate::opt::Style;
use crate::set::Set;
use crate::set::SetOpt;
use crate::Error;
use crate::Uid;

pub struct MultiOpt<T, S> {
    any_match: bool,

    sub_policys: Vec<T>,

    marker: PhantomData<S>,
}

impl<T, S> Debug for MultiOpt<T, S>
where
    T: Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("MultiOpt")
            .field("any_match", &self.any_match)
            .field("sub_policys", &self.sub_policys)
            .finish()
    }
}

impl<T, S> Clone for MultiOpt<T, S>
where
    T: Clone,
{
    fn clone(&self) -> Self {
        Self {
            any_match: self.any_match,
            sub_policys: self.sub_policys.clone(),
            marker: self.marker,
        }
    }
}

impl<T, S> Default for MultiOpt<T, S>
where
    T: Default,
{
    fn default() -> Self {
        Self {
            any_match: Default::default(),
            sub_policys: Default::default(),
            marker: PhantomData,
        }
    }
}

impl<T, S> MultiOpt<T, S> {
    pub fn with_any_match(mut self, any_match: bool) -> Self {
        self.any_match = any_match;
        self
    }

    pub fn with_sub_policy(mut self, single_opt: Vec<T>) -> Self {
        self.sub_policys = single_opt;
        self
    }

    pub fn any_match(&self) -> bool {
        self.any_match
    }

    pub fn add_sub_policy(&mut self, policy: T) -> &mut Self {
        self.sub_policys.push(policy);
        self
    }

    pub fn sub_policy(&self, idx: usize) -> Option<&T> {
        self.sub_policys.get(idx)
    }

    pub fn sub_policy_mut(&mut self, idx: usize) -> Option<&mut T> {
        self.sub_policys.get_mut(idx)
    }

    pub fn sub_policys(&self) -> &[T] {
        &self.sub_policys
    }

    pub fn sub_policys_mut(&mut self) -> &mut [T] {
        &mut self.sub_policys
    }

    pub fn len(&self) -> usize {
        self.sub_policys.len()
    }

    pub fn is_empty(&self) -> bool {
        self.sub_policys.is_empty()
    }
}

impl<T, S> MatchPolicy for MultiOpt<T, S>
where
    S: Set,
    SetOpt<S>: Opt,
    T: MatchPolicy<Set = S, Ret = bool, Error = Error>,
{
    type Set = S;

    type Ret = Option<usize>;

    type Error = Error;

    fn reset(&mut self) -> &mut Self {
        self.sub_policys.iter_mut().for_each(|v| {
            v.reset();
        });
        self
    }

    fn matched(&self) -> bool {
        if self.any_match {
            self.sub_policys.iter().any(MatchPolicy::matched)
        } else {
            self.sub_policys.iter().all(MatchPolicy::matched)
        }
    }

    fn undo(&mut self, uid: Uid, set: &mut Self::Set) -> Result<(), Self::Error> {
        if let Some(opt) = set.get_mut(uid) {
            opt.set_matched(false);
        }
        Ok(())
    }

    fn apply(&mut self, uid: Uid, set: &mut Self::Set) -> Result<(), Self::Error> {
        if let Some(opt) = set.get_mut(uid) {
            opt.set_matched(true);
        }
        Ok(())
    }

    fn filter(&mut self, uid: Uid, set: &mut Self::Set) -> bool {
        if let Some(opt) = set.get(uid) {
            !(opt.mat_style(Style::Argument)
                || opt.mat_style(Style::Boolean)
                || opt.mat_style(Style::Combined)
                || opt.mat_style(Style::Flag))
        } else {
            true
        }
    }

    fn r#match(
        &mut self,
        uid: Uid,
        set: &mut Self::Set,
        overload: bool,
        consume: bool,
    ) -> Result<Self::Ret, Self::Error> {
        for (index, sub_policy) in self.sub_policys.iter_mut().enumerate() {
            if sub_policy.r#match(uid, set, overload, consume)? {
                return Ok(Some(index));
            }
        }
        Ok(None)
    }
}