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> = 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>, } 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; fn next(&mut self) -> Option { 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 { elements: Vec, raw: RawCombinationsIterator, } impl CombinationsIterator { pub fn new(elements: impl IntoIterator, combinations_size: usize) -> Self { let elements: Vec<_> = elements.into_iter().collect(); let len = elements.len(); CombinationsIterator { elements, raw: RawCombinationsIterator::new(len, combinations_size), } } } impl Iterator for CombinationsIterator { type Item = Vec; fn next(&mut self) -> Option { 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'], ] ); } } }