combination 0.2.2

A lib to do math jobs like permutate and combinate data from vec.
Documentation
/// # InsufficientSize
///
/// it means that the index of select_list is over the element list length
#[derive(Debug)]
pub struct InsufficientSize {
    _err_index: usize,
}

impl InsufficientSize {
    pub fn new(err_index: usize) -> Self {
        Self {
            _err_index: err_index,
        }
    }
}

/// # Selector
///
/// by implement this trait, then make any type as a selector
///
/// pass this for the list, it can select value as this mode
///
/// # Example
/// ```
///struct CustomSelector;
///
///impl Selector for CustomSelector {
///   fn select_mode(&self) -> Vec<Vec<usize>> {
///       vec![vec![0, 0, 0], vec![1, 1, 1], vec![2, 2, 2]]
///   }
///}
///fn test_custom_selector() {
///   let str_list = ["how", "are", "u"];
///   let custom_selector = CustomSelector;
///   let res = str_list.try_select(&custom_selector).unwrap();
///
///   for v in res {
///      println!("{:#?}", v);
///   }
///}
///```
///
/// it will be
///
///
/// ```
/// [
///     ["how", "how", "how"],
///     ["are", "are", "are"],
///     ["u", "u", "u"]
/// ]
///
/// ```
pub trait Selector {
    fn select_mode(&self) -> Vec<Vec<usize>>;
}

/// # Select
///
/// this trait can allow any type select any ref from itself
///
/// whatever implements `Selector` can be used to select items from whatever implements `Select`
pub trait Select<T> {
    /// select a list from one `SelectList`
    fn select_one_list(&self, select_list: &[usize]) -> Vec<Option<&T>>;

    /// select a list of values
    ///
    /// if index is not in the list
    ///
    /// it will set as None
    ///
    /// works as `map(|val| self.select(val))`
    fn select<U: Selector>(&self, select_group: &U) -> Vec<Vec<Option<&T>>> {
        select_group
            .select_mode()
            .into_iter()
            .map(|s| self.select_one_list(&s))
            .collect()
    }

    /// select a list of values
    ///
    /// if index is not in the list
    ///
    /// it will return errortype
    fn try_select<U: Selector>(&self, select_group: &U) -> Result<Vec<Vec<&T>>, InsufficientSize> {
        let res: Vec<Result<Vec<&T>, usize>> = select_group
            .select_mode()
            .into_iter()
            .map(|list| {
                match self
                    .select_one_list(&list)
                    .iter()
                    .enumerate()
                    .find(|(_, v)| v.is_none())
                {
                    Some((index, _)) => Err(index),
                    None => Ok(self
                        .select_one_list(&list)
                        .into_iter()
                        .map(|v| v.unwrap())
                        .collect::<Vec<&T>>()),
                }
            })
            .collect();

        match res.iter().enumerate().find(|(_, v)| v.is_err()) {
            Some((index, _)) => Err(InsufficientSize::new(index)),
            None => Ok(res.into_iter().map(|list| list.unwrap()).collect()),
        }
    }
}

impl<T, const N: usize> Select<T> for [T; N] {
    fn select_one_list(&self, select_list: &[usize]) -> Vec<Option<&T>> {
        select_list.iter().map(|&i| self.get(i)).collect()
    }
}

macro_rules! select_impl {
    ($b:ident, $t:ty) => {
        impl<$b> Select<$b> for $t {
            fn select_one_list(&self, select_list: &[usize]) -> Vec<Option<&T>> {
                select_list.iter().map(|&i| self.get(i)).collect()
            }
        }
    };

    ($b:ident, $($t:ty),*) => {
       $(select_impl!($b, $t);)*
    };
}

// implement Select trait
select_impl!(T, &[T], Vec<T>, [T]);

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn test_select_from_str_list() {
        let str_list = ["hi", "i", "am", "roger", "and", "you"];
        let select_list = [1, 2, 3, 7, 2, 3, 0];
        let res = str_list.select_one_list(&select_list);

        for v in res {
            println!("{:#?}", v);
        }
    }

    struct CustomSelector;

    impl Selector for CustomSelector {
        fn select_mode(&self) -> Vec<Vec<usize>> {
            vec![vec![0, 0, 0], vec![1, 1, 1], vec![2, 2, 2]]
        }
    }

    #[test]
    fn test_custom_selector() {
        let str_list = ["hi", "i", "am", "roger", "and", "you"];
        let res = str_list.try_select(&CustomSelector).unwrap();

        println!("{:#?}", res);
    }
}