gear_combos 1.0.4

Attempts to make getting combinations of things easier with the use of gears and simple numeric states!
Documentation
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn reset_gears_sets_all_gears_states_back_to_0() {
        let mut gears = vec![Gear::new(3), Gear::new(3)];
        assert_eq!(0, gears[0].state());
        assert_eq!(0, gears[1].state());
        gears[0].next();
        gears[1].next();
        assert_eq!(1, gears[0].state());
        assert_eq!(1, gears[1].state());
        reset_gears(&mut gears);
        assert_eq!(0, gears[0].state());
        assert_eq!(0, gears[1].state());
    }

    #[test]
    fn get_gears_states_returns_all_states_in_vector() {
        let gears = vec![Gear::new(3), Gear::new(3)];
        assert_eq!(vec![0, 0], get_gears_states(&gears));
    }
    #[test]
    fn get_gears_states_returns_all_states_in_vector_after_changing_state() {
        let mut gears = vec![Gear::new(3), Gear::new(3)];
        gears[0].next();
        gears[0].next();
        gears[1].next();
        assert_eq!(vec![2, 1], get_gears_states(&gears));
    }

    #[test]
    fn get_gears_combinations_returns_vector_of_4_vectors_containing_each_combination() {
        let mut gears = vec![Gear::new(2), Gear::new(2)];
        let combos = get_gears_combinations(&mut gears);
        assert_eq!(4, combos.len());
        assert_eq!(vec![vec![0, 0], vec![1, 0], vec![0, 1], vec![1, 1]], combos);
    }
    #[test]
    fn get_gears_combinations_returns_vector_of_9_vectors_containing_each_combination() {
        let mut gears = vec![Gear::new(3), Gear::new(3)];
        let combos = get_gears_combinations(&mut gears);
        assert_eq!(9, combos.len());
        assert_eq!(
            vec![
                vec![0, 0],
                vec![1, 0],
                vec![2, 0],
                vec![0, 1],
                vec![1, 1],
                vec![2, 1],
                vec![0, 2],
                vec![1, 2],
                vec![2, 2]
            ],
            combos
        );
    }

    #[test]
    fn get_gears_combinations_returns_vector_of_12_vectors_containing_each_combination() {
        let mut gears = vec![Gear::new(2), Gear::new(2), Gear::new(3)];
        let combos = get_gears_combinations(&mut gears);
        assert_eq!(12,combos.len());
        assert_eq!(
            vec![
                vec![0, 0, 0],
                vec![1, 0, 0],
                vec![0, 1, 0],
                vec![1, 1, 0],
                vec![0, 0, 1],
                vec![1, 0, 1],
                vec![0, 1, 1],
                vec![1, 1, 1],
                vec![0, 0, 2],
                vec![1, 0, 2],
                vec![0, 1, 2],
                vec![1, 1, 2]
            ],
            combos
        );
    }
    #[test]
    fn get_gears_combinations_returns_vector_of_27_vectors_containing_each_combination() {
        let mut gears = vec![Gear::new(3), Gear::new(3), Gear::new(3)];
        let combos = get_gears_combinations(&mut gears);
        assert_eq!(27, combos.len());
        assert_eq!(
            vec![
                vec![0, 0, 0],
                vec![1, 0, 0],
                vec![2, 0, 0],
                vec![0, 1, 0],
                vec![1, 1, 0],
                vec![2, 1, 0],
                vec![0, 2, 0],
                vec![1, 2, 0],
                vec![2, 2, 0],
                vec![0, 0, 1],
                vec![1, 0, 1],
                vec![2, 0, 1],
                vec![0, 1, 1],
                vec![1, 1, 1],
                vec![2, 1, 1],
                vec![0, 2, 1],
                vec![1, 2, 1],
                vec![2, 2, 1],
                vec![0, 0, 2],
                vec![1, 0, 2],
                vec![2, 0, 2],
                vec![0, 1, 2],
                vec![1, 1, 2],
                vec![2, 1, 2],
                vec![0, 2, 2],
                vec![1, 2, 2],
                vec![2, 2, 2],
            ],
            combos
        );
    }
    #[test]
    fn gear_new_initializes_states() {
        let gear = Gear::new(3);
        assert!(!std::ptr::eq(&vec![0, 1, 2], gear.states()));
    }

    #[test]
    fn gear_new_sets_state_to_first() {
        let gear = Gear::new(3);
        assert_eq!(0, gear.state());
    }

    #[test]
    fn gear_next_increments_state_only_to_last_state() {
        let mut gear = Gear::new(3);
        assert_eq!(0, gear.state());
        gear.next();
        assert_eq!(1, gear.state());
        gear.next();
        assert_eq!(2, gear.state());
        gear.next();
        assert_eq!(2, gear.state());
    }
    #[test]
    fn gear_next_increments_state_returning_true_then_false_at_last_state() {
        let mut gear = Gear::new(3);
        assert_eq!(0, gear.state());
        assert!(gear.next());
        assert_eq!(1, gear.state());
        assert!(gear.next());
        assert_eq!(2, gear.state());
        assert!(!gear.next());
        assert_eq!(2, gear.state());
    }
    #[test]
    fn gear_next_increments_state_returning_true_then_false_at_last_state_until_reset() {
        let mut gear = Gear::new(3);
        assert_eq!(0, gear.state());
        assert!(gear.next());
        assert_eq!(1, gear.state());
        assert!(gear.next());
        assert_eq!(2, gear.state());
        assert!(!gear.next());
        assert_eq!(2, gear.state());
        gear.reset();
        assert_eq!(0, gear.state());
        assert!(gear.next());
    }
    #[test]
    fn gear_reset_sets_state_to_first() {
        let mut gear = Gear::new(3);
        assert_eq!(0, gear.state());
        gear.next();
        assert_eq!(1, gear.state());
        gear.next();
        assert_eq!(2, gear.state());
        gear.next();
        assert_eq!(2, gear.state());
        gear.reset();
        assert_eq!(0, gear.state());
    }

    #[test]
    fn gear_end_returns_true_when_at_last_state() {
        let mut gear = Gear::new(2);
        assert!(!gear.end());
        assert!(gear.next());
        assert!(gear.end());
    }

    #[test]
    fn gear_cycle_goes_through_all_states_and_back() {
        let mut gear = Gear::new(2);
        assert_eq!(0, gear.state());
        assert!(gear.cycle());
        assert_eq!(1, gear.state());
        assert!(!gear.cycle());
        assert_eq!(0, gear.state());
        assert!(gear.cycle());
        assert_eq!(1, gear.state());
    }
}

/// Represents a gear that can cycle through states.
/// It keeps track of the states available and which
/// state it is currently in.
pub struct Gear {
    states: Vec<i32>,
    state: usize,
}
impl Gear {
    /// Returns a new gear with an initial state of 0.
    /// Populates states with a vector starting from 0,
    /// until the end of 'size' - 1. 
    ///
    /// # Example
    /// ```
    /// use gear_combos::Gear;
    /// let gear = Gear::new(2);
    ///
    /// assert_eq!(&vec![0,1], gear.states());
    /// assert_eq!(0, gear.state());
    /// ```
    pub fn new(size: usize) -> Gear {
        let mut s: Vec<i32> = Vec::with_capacity(size);
        for i in 0..size {
            s.push(i as i32);
        }
        Gear {
            states: s,
            state: 0,
        }
    }
    /// Increments the state if it's not at the end.
    pub fn next(&mut self) -> bool {
        if self.end() {
            false // must reset
        } else {
            self.state += 1;
            true
        }
    }
    /// Increments the state and resets if at end.
    /// Returns true if the gear has increments.
    /// Returns false if the gear has been reset to 0;
    pub fn cycle(&mut self) -> bool {
        if self.next() {
            true
        } else {
            self.reset();
            false
        }
    }
    /// Returns whether the gear is at it's last state.
    pub fn end(&self) -> bool {
        self.state == self.states.len() - 1
    }
    /// Sets the gears state back to 0.
    pub fn reset(&mut self) {
        self.state = 0;
    }
    /// Returns a reference to the entire states of the gear.
    pub fn states(&self) -> &Vec<i32> {
        &self.states
    }
    /// Returns the current state of the gear.
    pub fn state(&self) -> i32 {
        self.states[self.state]
    }
}

/// Loops through each gear calling reset() on each.
///
/// # Example
///
/// ```
/// use gear_combos::*;
/// let mut gears = vec![Gear::new(3), Gear::new(3)];
/// assert_eq!(0, gears[0].state());
/// assert_eq!(0, gears[1].state());
/// gears[0].next();
/// gears[1].next();
/// assert_eq!(1, gears[0].state());
/// assert_eq!(1, gears[1].state());
/// reset_gears(&mut gears);
/// assert_eq!(0, gears[0].state());
/// assert_eq!(0, gears[1].state());
/// ```
pub fn reset_gears(gears: &mut Vec<Gear>) {
    for gear in gears {
        gear.reset();
    }
}

/// Returns a vector containing each state of the gears.
///
/// # Example
///
/// ```
/// use gear_combos::*;
/// let gears = vec![Gear::new(3), Gear::new(3)];
/// assert_eq!(vec![0, 0], get_gears_states(&gears));
/// ```
pub fn get_gears_states(gears: &Vec<Gear>) -> Vec<i32> {
    gears.iter().map(|g| g.state()).collect()
}

/// Returns a 2D vector containing every unique combination of states of the gears.
/// Begins by resetting each gear to it's initial state and progressively
/// cycling each gear from left to right.
///
/// # Example
///
/// ```
/// use gear_combos::*;
/// let mut gears = vec![Gear::new(2),Gear::new(2)];
/// let combos = get_gears_combinations(&mut gears);
///
/// assert_eq!(vec![vec![0,0],vec![1,0],vec![0,1],vec![1,1]],combos);
/// ```
pub fn get_gears_combinations(gears: &mut Vec<Gear>) -> Vec<Vec<i32>> {
    let mut combos: Vec<Vec<i32>> = Vec::with_capacity(gears.len());
    let mut finished = false;
    let last_index = gears.len() - 1;
    reset_gears(gears);
    combos.push(get_gears_states(gears)); // first vector of initial states

    while !finished {
        if !gears[0].cycle() {
            for (i, gear) in gears.iter_mut().enumerate() {
                if i == 0 {
                    continue;
                }
                if !gear.cycle() {
                    if i == last_index {
                        finished = true;
                        break;
                    }
                } else {
                    break;
                }
            }
        }
        if !finished {
            combos.push(get_gears_states(gears));
        }
    }

    combos
}