use std::ops::Deref;
use ssv::engine::domain::{BytesDomain, CharsDomain, Domain};
use crate::combinations::CombinationsIterator;
macro_rules! assert_roundtrip {
($domain:ident, $regular_elem:literal, $spacing_elem:literal, $quote_elem:literal) => {
use_domain_module!($domain);
for combinations_size in 0..=5 {
for elems in CombinationsIterator::new(
[$regular_elem, $spacing_elem, $quote_elem],
combinations_size,
) {
let string: <$domain as Domain>::String = elems.into_iter().collect();
let mut destination = Vec::new();
write(&mut destination, [[string.deref()]]).unwrap();
let values: ReadResult<Vec<_>> = read(destination.deref()).collect();
assert_eq!(values.unwrap(), [[string]]);
}
}
};
}
macro_rules! use_domain_module {
(BytesDomain) => {
use ssv::bytes::*;
};
(CharsDomain) => {
use ssv::chars::*;
};
}
#[test]
fn roundtrip_bytes() {
assert_roundtrip!(BytesDomain, b'x', b' ', b'"');
}
#[test]
fn roundtrip_chars() {
assert_roundtrip!(CharsDomain, 'x', ' ', '"');
}
mod combinations {
pub struct RawCombinationsIterator {
last_element: usize,
next_combination: Option<Vec<usize>>,
}
impl RawCombinationsIterator {
pub fn new(number_of_elements: usize, combinations_size: usize) -> Self {
RawCombinationsIterator {
last_element: number_of_elements - 1,
next_combination: Some(std::iter::repeat(0).take(combinations_size).collect()),
}
}
}
impl Iterator for RawCombinationsIterator {
type Item = Vec<usize>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(ref mut next_combination) = self.next_combination {
let to_return = next_combination.clone();
if next_combination.is_empty() {
self.next_combination = None;
} else {
for (i, element) in next_combination.iter_mut().enumerate().rev() {
if *element < self.last_element {
*element += 1;
break;
} else if i > 0 {
*element = 0;
continue;
} else {
self.next_combination = None;
break;
}
}
}
Some(to_return)
} else {
None
}
}
}
pub struct CombinationsIterator<T> {
elements: Vec<T>,
raw: RawCombinationsIterator,
}
impl<T> CombinationsIterator<T> {
pub fn new(elements: impl IntoIterator<Item = T>, combinations_size: usize) -> Self {
let elements: Vec<_> = elements.into_iter().collect();
let len = elements.len();
CombinationsIterator {
elements,
raw: RawCombinationsIterator::new(len, combinations_size),
}
}
}
impl<T: Clone> Iterator for CombinationsIterator<T> {
type Item = Vec<T>;
fn next(&mut self) -> Option<Self::Item> {
self.raw.next().map(|indexes| {
indexes
.iter()
.map(|index| self.elements[*index].clone())
.collect()
})
}
}
mod tests {
use super::*;
#[test]
fn combinations_raw() {
let values: Vec<_> = RawCombinationsIterator::new(3, 0).collect();
assert_eq!(values, vec![vec![]]);
let values: Vec<_> = RawCombinationsIterator::new(3, 3).collect();
assert_eq!(
values,
vec![
vec![0, 0, 0],
vec![0, 0, 1],
vec![0, 0, 2],
vec![0, 1, 0],
vec![0, 1, 1],
vec![0, 1, 2],
vec![0, 2, 0],
vec![0, 2, 1],
vec![0, 2, 2],
vec![1, 0, 0],
vec![1, 0, 1],
vec![1, 0, 2],
vec![1, 1, 0],
vec![1, 1, 1],
vec![1, 1, 2],
vec![1, 2, 0],
vec![1, 2, 1],
vec![1, 2, 2],
vec![2, 0, 0],
vec![2, 0, 1],
vec![2, 0, 2],
vec![2, 1, 0],
vec![2, 1, 1],
vec![2, 1, 2],
vec![2, 2, 0],
vec![2, 2, 1],
vec![2, 2, 2],
]
);
}
#[test]
fn combinations() {
let values: Vec<_> = CombinationsIterator::new(vec!['A', 'B', 'C'], 0).collect();
assert_eq!(values, vec![vec![]]);
let values: Vec<_> = CombinationsIterator::new(vec!['A', 'B', 'C'], 3).collect();
assert_eq!(
values,
vec![
vec!['A', 'A', 'A'],
vec!['A', 'A', 'B'],
vec!['A', 'A', 'C'],
vec!['A', 'B', 'A'],
vec!['A', 'B', 'B'],
vec!['A', 'B', 'C'],
vec!['A', 'C', 'A'],
vec!['A', 'C', 'B'],
vec!['A', 'C', 'C'],
vec!['B', 'A', 'A'],
vec!['B', 'A', 'B'],
vec!['B', 'A', 'C'],
vec!['B', 'B', 'A'],
vec!['B', 'B', 'B'],
vec!['B', 'B', 'C'],
vec!['B', 'C', 'A'],
vec!['B', 'C', 'B'],
vec!['B', 'C', 'C'],
vec!['C', 'A', 'A'],
vec!['C', 'A', 'B'],
vec!['C', 'A', 'C'],
vec!['C', 'B', 'A'],
vec!['C', 'B', 'B'],
vec!['C', 'B', 'C'],
vec!['C', 'C', 'A'],
vec!['C', 'C', 'B'],
vec!['C', 'C', 'C'],
]
);
}
}
}