#![cfg_attr(not(test), no_std)]
extern crate alloc;
use alloc::vec::{IntoIter, Vec};
#[derive(Debug)]
pub struct Combinatory<T> {
values: Vec<Vec<T>>,
current_combination_forwards: usize,
current_combination_backwards: usize,
forward_modules: Vec<usize>,
backward_modules: Vec<usize>,
direction_is_forward: bool,
combinations_len: usize,
}
impl<T> Combinatory<T> {
pub fn new<FirstLevelIter: IntoIterator<Item=SecondLevelIter>, SecondLevelIter: IntoIterator<Item=T>>(sentences: FirstLevelIter) -> Self {
let sentences = sentences.into_iter().map(|second_level| second_level.into_iter().collect::<Vec<_>>()).collect::<Vec<_>>();
let combinations_len =
sentences.iter()
.map(|sentences| sentences.into_iter().count()).reduce(|len1, len2| len1 * len2)
.unwrap();
let mut accumaleted_module = 1;
let mut forward_modules = Vec::new();
let mut iter_for_modules = sentences.iter().rev();
(0..sentences.iter().count()).for_each(|_| {
forward_modules.push(accumaleted_module);
accumaleted_module *= iter_for_modules.next().unwrap().len();
});
forward_modules.reverse();
let mut backward_modules = Vec::new();
let mut iter_for_modules = sentences.iter().rev();
(0..sentences.iter().count()).for_each(|_| {
backward_modules.push(accumaleted_module);
accumaleted_module *= iter_for_modules.next().unwrap().len();
});
backward_modules.reverse();
Self {
values: sentences,
current_combination_forwards: 0,
current_combination_backwards: combinations_len.checked_sub(1).unwrap_or(0),
forward_modules,
backward_modules,
direction_is_forward: true,
combinations_len: combinations_len,
}
}
}
impl<T> Combinatory<T> {
pub fn forward_direction(mut self) -> Self {
self.direction_is_forward = true;
self
}
pub fn backward_direction(mut self) -> Self {
self.direction_is_forward = true;
self
}
pub fn combination(&self, combination_index: usize) -> Option<impl DoubleEndedIterator<Item=&T>> {
if combination_index >= self.combinations_len {
return None;
}
let mut combinations = Vec::with_capacity(self.values.len());
for index in 0..self.values.len() {
let modules = if self.direction_is_forward { &self.forward_modules } else { &self.backward_modules };
combinations.push((combination_index / modules[index]) % self.values[index].len());
}
Some(combinations.into_iter().enumerate()
.map(|(level_1, level_2)| &self.values[level_1][level_2]))
}
pub fn ref_combinations(&self) -> impl DoubleEndedIterator<Item=impl DoubleEndedIterator<Item=&T>> {
(0..self.combinations_len)
.map(|combination| self.combination(combination).unwrap())
}
}
impl<T: Clone> DoubleEndedIterator for Combinatory<T> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.current_combination_backwards < self.current_combination_forwards {
return None;
}
let res = self.combination(self.current_combination_backwards)?
.map(|element| element.clone())
.collect::<Vec<_>>()
.into_iter();
self.current_combination_backwards -= 1;
Some(res)
}
}
impl<T: Clone> Iterator for Combinatory<T> {
type Item = IntoIter<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.current_combination_backwards < self.current_combination_forwards {
return None;
}
let res = self.combination(self.current_combination_forwards)?
.map(|element| element.clone())
.collect::<Vec<_>>()
.into_iter();
self.current_combination_forwards += 1;
Some(res)
}
}