#![no_std]
pub trait TuplePrepend<T> {
type ResultType;
fn prepend(self, t: T) -> Self::ResultType;
}
impl<T> TuplePrepend<T> for () {
type ResultType = (T,);
#[inline]
fn prepend(self, t: T) -> Self::ResultType {
(t,)
}
}
macro_rules! _impl_tuple_prepend {
( () ) => {};
( ($t:ident $( $typ:ident)* ) ) => {
impl<$t, $($typ,)* TT> TuplePrepend<TT> for ($t, $($typ,)*) {
type ResultType = (TT, $t, $($typ),*);
#[inline]
fn prepend(self, t: TT) -> Self::ResultType {
#[allow(non_snake_case)]
let ($t, $($typ,)*) = self;
(t, $t, $($typ,)*)
}
}
_impl_tuple_prepend!(($($typ)*));
}
}
_impl_tuple_prepend!((
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
));
#[macro_export]
macro_rules! cartesian {
($head:expr $(,)?) => {
$head.into_iter()
};
($head:expr, $tail:expr $(,)?) => {
cartesian!(@ $head.into_iter(), $tail.into_iter())
};
($head:expr $(, $tail:expr)+ $(,)?) => {
cartesian!(@ $head.into_iter(), cartesian!($($tail),+)).map(
|(head, tail)| $crate::TuplePrepend::prepend(tail, head)
)
};
(@ $head:expr, $tail:expr $(,)?) => {
$head.flat_map(|h| $tail.map(move |t| (h, t)))
};
}
#[cfg(test)]
extern crate alloc;
#[cfg(test)]
use alloc::{format, string::String, vec};
#[test]
fn two_combination() {
let mut acc = String::new();
for (a, b) in cartesian!(0..2, "xy".chars()) {
acc += &format!("{}{} ", a, b);
}
assert_eq!(acc, "0x 0y 1x 1y ");
}
#[test]
fn binary_numbers() {
let mut acc = String::new();
let range = 0..2;
let vec = vec![0, 1];
let string = vec![String::from("0"), String::from("1")];
for (a, b, c) in cartesian!(range, vec.iter(), string.iter()) {
acc += &format!("{}{}{} ", a, b, c);
}
assert_eq!(acc, "000 001 010 011 100 101 110 111 ");
}
#[test]
fn trailing_commas() {
let mut acc = String::new();
for a in cartesian!(
0..1,
) {
acc += &format!("{} ", a);
}
for (a, b) in cartesian!(
0..2,
0..2,
) {
acc += &format!("{}{} ", a, b);
}
for (a, b, c) in cartesian!(
0..2,
0..2,
0..2,
) {
acc += &format!("{}{}{} ", a, b, c);
}
assert_eq!(acc, "0 00 01 10 11 000 001 010 011 100 101 110 111 ");
}
#[test]
fn by_reference() {
let mut acc = String::new();
let outer = vec![String::from("a"), String::from("b")];
let inner = vec![String::from("0"), String::from("1")];
for (a, b) in cartesian!(&outer, &inner) {
acc += &format!("{}{} ", a, b);
}
assert_eq!(acc, "a0 a1 b0 b1 ");
}