#[macro_export]
macro_rules! count {
($type_:ty, $operation:path, $case:expr) => {
<$type_ as Metrics<dyn $operation>>::count($case)
};
}
#[macro_export]
macro_rules! output_mode {
($type_:ty, $operation:path, $case:expr) => {
<$type_ as OutputMode<dyn $operation>>::output_mode($case)
};
}
#[macro_export]
macro_rules! assert_count {
($type_:ty, $operation:path, $case:expr) => {{
$crate::print_scope!();
let Count(num_constants, num_public, num_private, num_constraints) = count!($type_, $operation, $case);
assert!(num_constants.matches(Circuit::num_constants_in_scope()), "(num_constants)");
assert!(num_public.matches(Circuit::num_public_in_scope()), "(num_public)");
assert!(num_private.matches(Circuit::num_private_in_scope()), "(num_private)");
assert!(num_constraints.matches(Circuit::num_constraints_in_scope()), "(num_constraints)");
assert!(Circuit::is_satisfied_in_scope(), "(is_satisfied_in_scope)");
}};
(FromBoolean($input:ident) => $output:ident, $case:expr) => {{
assert_count!($output<Circuit>, FromBoolean<Boolean = $input<Circuit>>, $case)
}};
($operation:tt<$boolean:ident>() => $output:ident, $case:expr) => {{
assert_count!($output<Circuit>, $operation<Boolean = $boolean<Circuit>>, $case)
}};
($operation:tt($input:ident) => $output:ident, $case:expr) => {{
assert_count!($input<Circuit>, $operation<Output = $output<Circuit>>, $case)
}};
($operation:tt($input_a:ident, $input_b:ident) => $output:ident, $case:expr) => {{
assert_count!($input_a<Circuit>, $operation<$input_b<Circuit>, Output = $output<Circuit>>, $case)
}};
($operation:tt($boolean:ident, $input_a:ident, $input_b:ident) => $output:ident, $case:expr) => {{
assert_count!($input_a<Circuit>, $operation<Boolean = $boolean<Circuit>, Output = $output<Circuit>>, $case)
}};
($operation:tt<$boolean:ident>() => $output:ident<$($parameter:ident),+>, $case:expr) => {{
assert_count!($output<Circuit, $($parameter),+>, $operation<Boolean = $boolean<Circuit>>, $case)
}};
($operation:tt($input:ident<$($parameter_a:ident),+>) => $output:ident<$($parameter_b:ident),+>, $case:expr) => {{
assert_count!($input<Circuit, $($parameter_a),+>, $operation<Output = $output<Circuit, $($parameter_b),+>>, $case)
}};
($operation:tt($input_a:ident<$($parameter_a:ident),+>, $input_b:ident<$($parameter_b:ident),+>) => $output:ident, $case:expr) => {{
assert_count!($input_a<Circuit, $($parameter_a),+>, $operation<$input_b<Circuit, $($parameter_b),+>, Output = $output<Circuit>>, $case)
}};
($operation:tt($input_a:ident<$($parameter_a:ident),+>, $input_b:ident<$($parameter_b:ident),+>) => $output:ident<$($parameter_c:ident),+>, $case:expr) => {{
assert_count!($input_a<Circuit, $($parameter_a),+>, $operation<$input_b<Circuit, $($parameter_b),+>, Output = $output<Circuit, $($parameter_c),+>>, $case)
}};
($operation:tt($boolean:ident, $input_a:ident<$($parameter_a:ident),+>, $input_b:ident<$($parameter_b:ident),+>) => $output:ident<$($parameter_c:ident),+>, $case:expr) => {{
assert_count!($input_a<Circuit, $($parameter_a),+>, $operation<Boolean = $boolean<Circuit>, Output = $output<Circuit, $($parameter_c),+>>, $case)
}};
}
#[macro_export]
macro_rules! assert_count_fails {
($type_:ty, $operation:path, $case:expr) => {{
$crate::print_scope!();
let Count(num_constants, num_public, num_private, num_constraints) = count!($type_, $operation, $case);
assert!(num_constants.matches(Circuit::num_constants_in_scope()), "(num_constants)");
assert!(num_public.matches(Circuit::num_public_in_scope()), "(num_public)");
assert!(num_private.matches(Circuit::num_private_in_scope()), "(num_private)");
assert!(num_constraints.matches(Circuit::num_constraints_in_scope()), "(num_constraints)");
assert!(!Circuit::is_satisfied_in_scope(), "(!is_satisfied_in_scope)");
}};
(FromBoolean($input:ident) => $output:ident, $case:expr) => {{
assert_count_fails!($output<Circuit>, FromBoolean<Boolean = $input<Circuit>>, $case)
}};
($operation:tt<$boolean:ident>() => $output:ident, $case:expr) => {{
assert_count_fails!($output<Circuit>, $operation<Boolean = $boolean<Circuit>>, $case)
}};
($operation:tt($input:ident) => $output:ident, $case:expr) => {{
assert_count_fails!($input<Circuit>, $operation<Output = $output<Circuit>>, $case)
}};
($operation:tt($input_a:ident, $input_b:ident) => $output:ident, $case:expr) => {{
assert_count_fails!($input_a<Circuit>, $operation<$input_b<Circuit>, Output = $output<Circuit>>, $case)
}};
($operation:tt($boolean:ident, $input_a:ident, $input_b:ident) => $output:ident, $case:expr) => {{
assert_count_fails!($input_a<Circuit>, $operation<Boolean = $boolean<Circuit>, Output = $output<Circuit>>, $case)
}};
($operation:tt<$boolean:ident>() => $output:ident<$($parameter:ident),+>, $case:expr) => {{
assert_count_fails!($output<Circuit, $($parameter),+>, $operation<Boolean = $boolean<Circuit>>, $case)
}};
($operation:tt($input:ident<$($parameter_a:ident),+>) => $output:ident<$($parameter_b:ident),+>, $case:expr) => {{
assert_count_fails!($input<Circuit, $($parameter_a),+>, $operation<Output = $output<Circuit, $($parameter_b),+>>, $case)
}};
($operation:tt($input_a:ident<$($parameter_a:ident),+>, $input_b:ident<$($parameter_b:ident),+>) => $output:ident, $case:expr) => {{
assert_count_fails!($input_a<Circuit, $($parameter_a),+>, $operation<$input_b<Circuit, $($parameter_b),+>, Output = $output<Circuit>>, $case)
}};
($operation:tt($input_a:ident<$($parameter_a:ident),+>, $input_b:ident<$($parameter_b:ident),+>) => $output:ident<$($parameter_c:ident),+>, $case:expr) => {{
assert_count_fails!($input_a<Circuit, $($parameter_a),+>, $operation<$input_b<Circuit, $($parameter_b),+>, Output = $output<Circuit, $($parameter_c),+>>, $case)
}};
($operation:tt($boolean:ident, $input_a:ident<$($parameter_a:ident),+>, $input_b:ident<$($parameter_b:ident),+>) => $output:ident<$($parameter_c:ident),+>, $case:expr) => {{
assert_count_fails!($input_a<Circuit, $($parameter_a),+>, $operation<Boolean = $boolean<Circuit>, Output = $output<Circuit, $($parameter_c),+>>, $case)
}};
}
#[macro_export]
macro_rules! assert_output_mode {
($type_:ty, $operation:path, $case:expr, $candidate:expr) => {{
let expected_mode = output_mode!($type_, $operation, $case);
assert_eq!(expected_mode, $candidate.eject_mode());
}};
(FromBoolean($input:ident) => $output:ident, $case:expr, $candidate:expr) => {{
assert_output_mode!($output<Circuit>, FromBoolean<Boolean = $input<Circuit>>, $case, $candidate)
}};
($operation:tt<$boolean:ident>() => $output:ident, $case:expr, $candidate:expr) => {{
assert_output_mode!($output<Circuit>, $operation<Boolean = $boolean<Circuit>>, $case, $candidate)
}};
($operation:tt($input:ident) => $output:ident, $case:expr, $candidate:expr) => {{
assert_output_mode!($input<Circuit>, $operation<Output = $output<Circuit>>, $case, $candidate)
}};
($operation:tt($input_a:ident, $input_b:ident) => $output:ident, $case:expr, $candidate:expr) => {{
assert_output_mode!($input_a<Circuit>, $operation<$input_b<Circuit>, Output = $output<Circuit>>, $case, $candidate)
}};
($operation:tt($boolean:ident, $input_a:ident, $input_b:ident) => $output:ident, $case:expr, $candidate:expr) => {{
assert_output_mode!($input_a<Circuit>, $operation<Boolean = $boolean<Circuit>, Output = $output<Circuit>>, $case, $candidate)
}};
($operation:tt<$boolean:ident>() => $output:ident<$($parameter:ident),+>, $case:expr, $candidate:expr) => {{
assert_output_mode!($output<Circuit, $($parameter),+>, $operation<Boolean = $boolean<Circuit>>, $case, $candidate)
}};
($operation:tt($input:ident<$($parameter_a:ident),+>) => $output:ident<$($parameter_b:ident),+>, $case:expr, $candidate:expr) => {{
assert_output_mode!($input<Circuit, $($parameter_a),+>, $operation<Output = $output<Circuit, $($parameter_b),+>>, $case, $candidate)
}};
($operation:tt($input_a:ident<$($parameter_a:ident),+>, $input_b:ident<$($parameter_b:ident),+>) => $output:ident, $case:expr, $candidate:expr) => {{
assert_output_mode!($input_a<Circuit, $($parameter_a),+>, $operation<$input_b<Circuit, $($parameter_b),+>, Output = $output<Circuit>>, $case, $candidate)
}};
($operation:tt($input_a:ident<$($parameter_a:ident),+>, $input_b:ident<$($parameter_b:ident),+>) => $output:ident<$($parameter_c:ident),+>, $case:expr, $candidate:expr) => {{
assert_output_mode!($input_a<Circuit, $($parameter_a),+>, $operation<$input_b<Circuit, $($parameter_b),+>, Output = $output<Circuit, $($parameter_c),+>>, $case, $candidate)
}};
($operation:tt($boolean:ident, $input_a:ident<$($parameter_a:ident),+>, $input_b:ident<$($parameter_b:ident),+>) => $output:ident<$($parameter_c:ident),+>, $case:expr, $candidate:expr) => {{
assert_output_mode!($input_a<Circuit, $($parameter_a),+>, $operation<Boolean = $boolean<Circuit>, Output = $output<Circuit, $($parameter_c),+>>, $case, $candidate)
}};
}