#![forbid(missing_docs)]
pub mod dispatchers;
pub mod prelude;
pub mod std_enums;
#[macro_export]
macro_rules! implement_dispatcher_trait {
(
$enum_name:ident ( $( $ty_arg:tt ),* $( , )? ),
$( (
$variant_name:ident,
$inner_type:ty,
$container_name:ident,
$container_letter:ident
) ),+ $( , )?
) => {
impl<
$( $ty_arg, )*
$( $container_letter, )+
> $crate::dispatchers::Dispatch<( $( $container_letter, )+ )> for $enum_name< $( $ty_arg, )* >
where
$(
$container_letter: Default + Extend<$inner_type>,
)+
{
fn dispatch<I>(iter: I) -> ( $( $container_letter, )+ )
where
I: Iterator<Item = $enum_name< $( $ty_arg, )* >>,
{
$(
let mut $container_name = $container_letter::default();
)+
use $enum_name::*;
for element in iter {
match element {
$(
$variant_name(value) => $container_name.extend(Some(value)),
)+
}
}
(
$(
$container_name,
)+
)
}
}
}
}
#[macro_export]
macro_rules! implement_dispatch {
($_:ident $( < $( $__:tt ),+ $( , )? > )? $( , )? ) => {
compile_error!("It is not necessary to implement `Dispatch` on an empty enum.");
};
($_:ident $( < $( $__:tt),+ $( , )? > )?,
$___: ident ($____: ty) $( , )?
) => {
compile_error!("It is not necessary to implement `Dispatch` on a single-variant enum. You can use `map` and then collect instead.");
};
($enum_name:ident $( < $( $ty_arg:tt ),+ $( , )? > )?,
$variant1_name: ident ($variant1_it: ty),
$variant2_name: ident ($variant2_it: ty) $( , )?
) => {
implement_dispatcher_trait!(
$enum_name( $( $( $ty_arg, )+ )? ),
($variant1_name, $variant1_it, container_a, A),
($variant2_name, $variant2_it, container_b, B),
);
};
($enum_name:ident $( < $( $ty_arg:tt ),+ $( , )? > )?,
$variant1_name: ident ($variant1_it: ty),
$variant2_name: ident ($variant2_it: ty),
$variant3_name: ident ($variant3_it: ty) $( , )?
) => {
implement_dispatcher_trait!(
$enum_name( $( $( $ty_arg, )+ )? ),
($variant1_name, $variant1_it, container_1, A),
($variant2_name, $variant2_it, container_2, B),
($variant3_name, $variant3_it, container_3, C),
);
};
($enum_name:ident $( < $( $ty_arg:tt ),+ $( , )? > )?,
$variant1_name: ident ($variant1_it: ty),
$variant2_name: ident ($variant2_it: ty),
$variant3_name: ident ($variant3_it: ty),
$variant4_name: ident ($variant4_it: ty) $( , )?
) => {
implement_dispatcher_trait!(
$enum_name( $( $( $ty_arg, )+ )? ),
($variant1_name, $variant1_it, container_1, A),
($variant2_name, $variant2_it, container_2, B),
($variant3_name, $variant3_it, container_3, C),
($variant4_name, $variant4_it, container_4, D),
);
};
($enum_name:ident $( < $( $ty_arg:tt ),+ $( , )? > )?,
$variant1_name: ident ($variant1_it: ty),
$variant2_name: ident ($variant2_it: ty),
$variant3_name: ident ($variant3_it: ty),
$variant4_name: ident ($variant4_it: ty),
$variant5_name: ident ($variant5_it: ty) $( , )?
) => {
implement_dispatcher_trait!(
$enum_name( $( $( $ty_arg, )+ )? ),
($variant1_name, $variant1_it, container_1, A),
($variant2_name, $variant2_it, container_2, B),
($variant3_name, $variant3_it, container_3, C),
($variant4_name, $variant4_it, container_4, D),
($variant5_name, $variant5_it, container_5, E),
);
};
($enum_name:ident $( < $( $ty_arg:tt ),+ $( , )? > )?,
$variant1_name: ident ($variant1_it: ty),
$variant2_name: ident ($variant2_it: ty),
$variant3_name: ident ($variant3_it: ty),
$variant4_name: ident ($variant4_it: ty),
$variant5_name: ident ($variant5_it: ty),
$variant6_name: ident ($variant6_it: ty) $( , )?
) => {
implement_dispatcher_trait!(
$enum_name( $( $( $ty_arg, )+ )? ),
($variant1_name, $variant1_it, container_1, A),
($variant2_name, $variant2_it, container_2, B),
($variant3_name, $variant3_it, container_3, C),
($variant4_name, $variant4_it, container_4, D),
($variant5_name, $variant5_it, container_5, E),
($variant6_name, $variant6_it, container_6, F),
);
};
($enum_name:ident $( < $( $ty_arg:tt ),+ $( , )? > )?,
$variant1_name: ident ($variant1_it: ty),
$variant2_name: ident ($variant2_it: ty),
$variant3_name: ident ($variant3_it: ty),
$variant4_name: ident ($variant4_it: ty),
$variant5_name: ident ($variant5_it: ty),
$variant6_name: ident ($variant6_it: ty),
$variant7_name: ident ($variant7_it: ty) $( , )?
) => {
implement_dispatcher_trait!(
$enum_name( $( $( $ty_arg, )+ )? ),
($variant1_name, $variant1_it, container_1, A),
($variant2_name, $variant2_it, container_2, B),
($variant3_name, $variant3_it, container_3, C),
($variant4_name, $variant4_it, container_4, D),
($variant5_name, $variant5_it, container_5, E),
($variant6_name, $variant6_it, container_6, F),
($variant7_name, $variant7_it, container_7, G),
);
};
($enum_name:ident $( < $( $ty_arg:tt ),+ $( , )? > )?,
$variant1_name: ident ($variant1_it: ty),
$variant2_name: ident ($variant2_it: ty),
$variant3_name: ident ($variant3_it: ty),
$variant4_name: ident ($variant4_it: ty),
$variant5_name: ident ($variant5_it: ty),
$variant6_name: ident ($variant6_it: ty),
$variant7_name: ident ($variant7_it: ty),
$variant8_name: ident ($variant8_it: ty) $( , )?
) => {
implement_dispatcher_trait!(
$enum_name( $( $( $ty_arg, )+ )? ),
($variant1_name, $variant1_it, container_1, A),
($variant2_name, $variant2_it, container_2, B),
($variant3_name, $variant3_it, container_3, C),
($variant4_name, $variant4_it, container_4, D),
($variant5_name, $variant5_it, container_5, E),
($variant6_name, $variant6_it, container_6, F),
($variant7_name, $variant7_it, container_7, G),
($variant8_name, $variant8_it, container_8, H),
);
};
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! implement_and_test_dispatching {
(
$test_name:ident,
// The values which will be yielded by the iterator
[ $( $input_value:expr ),* $( , )? ],
// Informations about each variant
$( (
// The name of the variant
$v_name:ident
// Its inner type
($v_type:ty),
// The name of its container
$c_name:ident,
// The type of its container
$collect_type:ty,
// The expected content of the container
$c_content:tt $( , )?
) ),* $( , )?
) => {
#[test]
fn $test_name() {
use crate::prelude::*;
enum Enum {
$( $v_name($v_type) ),*
}
use Enum::*;
implement_dispatch!(
Enum,
$( $v_name($v_type) ),*
);
let iter = vec![ $( $input_value ),* ].into_iter();
let ( $( $c_name ),* ): ( $( $collect_type ),* ) = Enum::dispatch(iter);
$(
assert_eq!($c_name, $c_content);
)*
}
};
}
implement_and_test_dispatching! {
dispatch_enum2,
[V1(42), V2("manatee")],
(V1(usize), c1, Vec<_>, [42]),
(V2(&'static str), c2, Vec<_>, ["manatee"]),
}
implement_and_test_dispatching! {
dispatch_enum3,
[V1(42), V2("manatee"), V3('!')],
(V1(usize), c1, Vec<_>, [42]),
(V2(&'static str), c2, Vec<_>, ["manatee"]),
(V3(char), c3, Vec<_>, ['!']),
}
implement_and_test_dispatching! {
dispatch_enum4,
[V1(42), V2("manatee"), V3('!'), V4(true)],
(V1(usize), c1, Vec<_>, [42]),
(V2(&'static str), c2, Vec<_>, ["manatee"]),
(V3(char), c3, Vec<_>, ['!']),
(V4(bool), c4, Vec<_>, [true]),
}
implement_and_test_dispatching! {
dispatch_enum5,
[V1(42), V2("manatee"), V3('!'), V4(true), V5(1.618)],
(V1(usize), c1, Vec<_>, [42]),
(V2(&'static str), c2, Vec<_>, ["manatee"]),
(V3(char), c3, Vec<_>, ['!']),
(V4(bool), c4, Vec<_>, [true]),
(V5(f64), c5, Vec<_>, [1.618]),
}
implement_and_test_dispatching! {
dispatch_enum6,
[V1(42), V2("manatee"), V3('!'), V4(true), V5(1.618), V6(-1)],
(V1(usize), c1, Vec<_>, [42]),
(V2(&'static str), c2, Vec<_>, ["manatee"]),
(V3(char), c3, Vec<_>, ['!']),
(V4(bool), c4, Vec<_>, [true]),
(V5(f64), c5, Vec<_>, [1.618]),
(V6(isize), c6, Vec<_>, [-1]),
}
implement_and_test_dispatching! {
dispatch_enum7,
[V1(42), V2("manatee"), V3('!'), V4(true), V5(1.618), V6(-1), V7(101)],
(V1(usize), c1, Vec<_>, [42]),
(V2(&'static str), c2, Vec<_>, ["manatee"]),
(V3(char), c3, Vec<_>, ['!']),
(V4(bool), c4, Vec<_>, [true]),
(V5(f64), c5, Vec<_>, [1.618]),
(V6(isize), c6, Vec<_>, [-1]),
(V7(u8), c7, Vec<_>, [101]),
}
implement_and_test_dispatching! {
dispatch_enum8,
[V1(42), V2("manatee"), V3('!'), V4(true), V5(1.618), V6(-1), V7(101), V8('§')],
(V1(usize), c1, Vec<_>, [42]),
(V2(&'static str), c2, Vec<_>, ["manatee"]),
(V3(char), c3, Vec<_>, ['!']),
(V4(bool), c4, Vec<_>, [true]),
(V5(f64), c5, Vec<_>, [1.618]),
(V6(isize), c6, Vec<_>, [-1]),
(V7(u8), c7, Vec<_>, [101]),
(V8(char), c8, Vec<_>, ['§']),
}
}