macro_rules! define_iter {
    ($name:ident, $num:ident, $($case:ident),+) => {
        #[doc = concat!("Allows ", stringify!($num), " different `Iterator` types to be merged to a single iterator type.")]
        pub enum $name<$($case),+> {
            $($case($case)),+
        }

        impl<Item, $($case),+> Iterator for $name<$($case),+>
        where $($case: Iterator<Item = Item>),+ {
            type Item = Item;

            fn next(&mut self) -> Option<Self::Item> {
                match self {
                    $(Self::$case(inner) => inner.next(),)+
                }
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                match self {
                    $(Self::$case(inner) => inner.size_hint(),)+
                }
            }
        }

        impl<Item, $($case),+> DoubleEndedIterator for $name<$($case),+>
        where $($case: DoubleEndedIterator<Item = Item>),+ {
            fn next_back(&mut self) -> Option<Self::Item> {
                match self {
                    $(Self::$case(inner) => inner.next_back(),)+
                }
            }
        }

        impl<Item, $($case),+> ExactSizeIterator for $name<$($case),+>
        where $($case: ExactSizeIterator<Item = Item>),+ {}
    }
}

define_iter!(Iter2, two, A, B);
define_iter!(Iter3, three, A, B, C);
define_iter!(Iter4, four, A, B, C, D);
define_iter!(Iter5, five, A, B, C, D, E);
define_iter!(Iter6, six, A, B, C, D, E, F);
define_iter!(Iter7, seven, A, B, C, D, E, F, G);
define_iter!(Iter8, eight, A, B, C, D, E, F, G, H);
define_iter!(Iter9, nine, A, B, C, D, E, F, G, H, I);
