clap_conf 0.2.0

A library to unify commandline arguments with config files and environment variables. And make it easier for users to tell your program how to behave across the three main input sources
Documentation
use crate::{Filter, Getter};
use std::fmt::{Debug, Display};
use std::path::PathBuf;

#[derive(Debug)]
pub struct Holder<A, B> {
    a: A,
    b: B,
}

impl<'a, A, B> Holder<A, B>
where
    A: Getter<'a>,
    B: Getter<'a>,
    A::Out: std::convert::From<B::Out> + Debug + PartialEq + Display,
{
    pub fn new(a: A, b: B) -> Self {
        Holder { a, b }
    }
}

#[derive(Debug)]
pub enum OrIter<A: Iterator, B: Iterator> {
    A(A),
    B(B),
}

impl<R, R2, A, B> Iterator for OrIter<A, B>
where
    A: Iterator<Item = R>,
    B: Iterator<Item = R2>,
    R: std::convert::From<R2>,
{
    type Item = R;
    fn next(&mut self) -> Option<R> {
        match self {
            OrIter::A(a) => a.next(),
            OrIter::B(b) => b.next().map(|x| x.into()),
        }
    }
}

impl<'a, A, B> Getter<'a> for Holder<A, B>
where
    A: Getter<'a>,
    B: Getter<'a>,
    A::Out: std::convert::From<B::Out>,
{
    type Out = A::Out;
    type Iter = OrIter<A::Iter, B::Iter>;
    fn bool_flag<S: AsRef<str>>(&self, s: S, f: Filter) -> bool {
        self.a.bool_flag(s.as_ref(), f) || self.b.bool_flag(s, f)
    }

    fn value<S: AsRef<str>>(&self, s: S, f: Filter) -> Option<A::Out> {
        self.a
            .value(s.as_ref(), f)
            .or_else(|| self.b.value(s, f).map(|r| r.into()))
    }

    fn values<S: AsRef<str>>(&self, s: S, f: Filter) -> Option<OrIter<A::Iter, B::Iter>> {
        if let Some(r) = self.a.values(s.as_ref(), f) {
            return Some(OrIter::A(r.into_iter()));
        }
        if let Some(r) = self.b.values(s.as_ref(), f) {
            return Some(OrIter::B(r.into_iter()));
        }
        None
    }

    fn local_value<S: AsRef<str>>(&self, s: S, f: Filter) -> Option<PathBuf> {
        self.a
            .local_value(s.as_ref(), f)
            .or_else(|| self.b.local_value(s, f).map(|r| r.into()))
    }

    fn sub<S: AsRef<str>>(&self, s: S, f: Filter) -> bool {
        self.a.sub(s.as_ref(), f) || self.b.sub(s, f)
    }
}

#[derive(Debug)]
pub struct ConvIter<I, F> {
    it: I,
    f: F,
}

impl<R, R2, I, F> Iterator for ConvIter<I, F>
where
    I: Iterator<Item = R>,
    F: Fn(R) -> R2,
{
    type Item = R2;
    fn next(&mut self) -> Option<R2> {
        self.it.next().map(&self.f)
    }
}

#[derive(Debug)]
pub struct Wrapper<G, F> {
    pub g: G,
    pub f: F,
}

impl<G, F> Wrapper<G, F> {
    pub fn new(g: G, f: F) -> Self {
        Wrapper { g, f }
    }
}

impl<'a, G, R, F> Getter<'a> for Wrapper<G, F>
where
    G: Getter<'a>,
    F: Fn(G::Out) -> R + Clone,
    G::Out: PartialEq + Debug + Display,
    R: PartialEq + Debug + Display,
{
    type Out = R;
    type Iter = ConvIter<G::Iter, F>;
    fn bool_flag<S: AsRef<str>>(&self, s: S, f: Filter) -> bool {
        self.g.bool_flag(s, f)
    }
    fn value<S: AsRef<str>>(&self, s: S, f: Filter) -> Option<R> {
        self.g.value(s, f).map(&self.f)
    }

    fn values<S: AsRef<str>>(&self, s: S, f: Filter) -> Option<Self::Iter> {
        Some(ConvIter {
            it: self.g.values(s, f)?,
            f: self.f.clone(),
        })
    }

    fn local_value<S: AsRef<str>>(&self, s: S, f: Filter) -> Option<PathBuf> {
        self.g.local_value(s, f)
    }

    fn sub<S: AsRef<str>>(&self, s: S, f: Filter) -> bool {
        self.g.sub(s, f)
    }
}

#[derive(Debug)]
pub struct Localizer<G> {
    local: PathBuf,
    g: G,
}

impl<G> Localizer<G> {
    pub fn new<P>(g: G, p: P) -> Self
    where
        PathBuf: From<P>,
    {
        Localizer {
            g,
            local: PathBuf::from(p),
        }
    }
}

impl<'a, G> Getter<'a> for Localizer<G>
where
    G: Getter<'a>,
{
    type Out = G::Out;
    type Iter = G::Iter;
    fn bool_flag<S: AsRef<str>>(&self, s: S, f: Filter) -> bool {
        self.g.bool_flag(s, f)
    }
    fn value<S: AsRef<str>>(&self, s: S, f: Filter) -> Option<G::Out> {
        self.g.value(s, f)
    }

    fn values<S: AsRef<str>>(&self, s: S, f: Filter) -> Option<Self::Iter> {
        self.g.values(s, f)
    }

    fn sub<S: AsRef<str>>(&self, s: S, f: Filter) -> bool {
        self.g.sub(s, f)
    }

    fn local_value<S: AsRef<str>>(&self, s: S, f: Filter) -> Option<PathBuf> {
        self.g.local_value(s, f).map(|iv| match iv.is_absolute() {
            true => iv,
            false => self.local.clone().join(iv),
        })
    }
}