1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#[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)
}};
}