Skip to main content

snarkvm_circuit_types_integers/
lib.rs

1// Copyright (c) 2019-2026 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#![forbid(unsafe_code)]
17#![allow(clippy::too_many_arguments)]
18#![cfg_attr(test, allow(clippy::assertions_on_result_states))]
19
20extern crate snarkvm_console_types_integers as console;
21
22mod helpers;
23
24pub mod abs_checked;
25pub mod abs_wrapped;
26pub mod add_checked;
27pub mod add_wrapped;
28pub mod and;
29pub mod compare;
30pub mod div_checked;
31pub mod div_wrapped;
32pub mod equal;
33pub mod modulo;
34pub mod mul_checked;
35pub mod mul_wrapped;
36pub mod neg;
37pub mod not;
38pub mod or;
39pub mod pow_checked;
40pub mod pow_wrapped;
41pub mod rem_checked;
42pub mod rem_wrapped;
43pub mod shl_checked;
44pub mod shl_wrapped;
45pub mod shr_checked;
46pub mod shr_wrapped;
47pub mod sub_checked;
48pub mod sub_wrapped;
49pub mod ternary;
50pub mod xor;
51
52pub type I8<E> = Integer<E, i8>;
53pub type I16<E> = Integer<E, i16>;
54pub type I32<E> = Integer<E, i32>;
55pub type I64<E> = Integer<E, i64>;
56pub type I128<E> = Integer<E, i128>;
57
58pub type U8<E> = Integer<E, u8>;
59pub type U16<E> = Integer<E, u16>;
60pub type U32<E> = Integer<E, u32>;
61pub type U64<E> = Integer<E, u64>;
62pub type U128<E> = Integer<E, u128>;
63
64#[cfg(test)]
65use snarkvm_circuit_environment::{
66    assert_count,
67    assert_count_fails,
68    assert_output_mode,
69    assert_scope,
70    count,
71    output_mode,
72};
73#[cfg(test)]
74use snarkvm_utilities::{TestRng, Uniform};
75
76use snarkvm_circuit_environment::prelude::*;
77use snarkvm_circuit_types_boolean::Boolean;
78use snarkvm_circuit_types_field::Field;
79use snarkvm_circuit_types_scalar::Scalar;
80
81use core::marker::PhantomData;
82
83#[derive(Clone)]
84pub struct Integer<E: Environment, I: IntegerType> {
85    bits_le: Vec<Boolean<E>>,
86    phantom: PhantomData<I>,
87}
88
89impl<E: Environment, I: IntegerType> IntegerTrait<I, U8<E>, U16<E>, U32<E>> for Integer<E, I> {}
90
91impl<E: Environment, I: IntegerType> IntegerCore<I> for Integer<E, I> {}
92
93impl<E: Environment, I: IntegerType> Integer<E, I> {
94    /// Returns the size of the integer in bits.
95    pub fn size_in_bits() -> u16 {
96        I::BITS as u16
97    }
98
99    /// Casts the integer to its dual type, i.e., from signed to unsigned or vice versa.
100    pub fn cast_as_dual(self) -> Integer<E, I::Dual> {
101        Integer::<E, I::Dual> { bits_le: self.bits_le, phantom: Default::default() }
102    }
103}
104
105impl<E: Environment, I: IntegerType> Inject for Integer<E, I> {
106    type Primitive = console::Integer<E::Network, I>;
107
108    /// Initializes a new integer.
109    fn new(mode: Mode, value: Self::Primitive) -> Self {
110        let mut bits_le = Vec::with_capacity(I::BITS as usize);
111        let mut value = *value;
112        for _ in 0..I::BITS {
113            bits_le.push(Boolean::new(mode, value & I::one() == I::one()));
114            value = value.wrapping_shr(1u32);
115        }
116        Self::from_bits_le(&bits_le)
117    }
118}
119
120impl<E: Environment, I: IntegerType> Eject for Integer<E, I> {
121    type Primitive = console::Integer<E::Network, I>;
122
123    /// Ejects the mode of the integer.
124    fn eject_mode(&self) -> Mode {
125        self.bits_le.eject_mode()
126    }
127
128    /// Ejects the integer circuit as a console integer value.
129    fn eject_value(&self) -> Self::Primitive {
130        self.bits_le.iter().rev().fold(console::Integer::zero(), |value, bit| match bit.eject_value() {
131            true => console::Integer::new((value.wrapping_shl(1)) ^ I::one()),
132            false => console::Integer::new((value.wrapping_shl(1)) ^ I::zero()),
133        })
134    }
135}
136
137impl<E: Environment, I: IntegerType> Parser for Integer<E, I> {
138    /// Parses a string into an integer circuit.
139    #[inline]
140    fn parse(string: &str) -> ParserResult<Self> {
141        // Parse the integer from the string.
142        let (string, integer) = console::Integer::parse(string)?;
143        // Parse the mode from the string.
144        let (string, mode) = opt(pair(tag("."), Mode::parse))(string)?;
145
146        match mode {
147            Some((_, mode)) => Ok((string, Integer::new(mode, integer))),
148            None => Ok((string, Integer::new(Mode::Constant, integer))),
149        }
150    }
151}
152
153impl<E: Environment, I: IntegerType> FromStr for Integer<E, I> {
154    type Err = Error;
155
156    /// Parses a string into an integer circuit.
157    #[inline]
158    fn from_str(string: &str) -> Result<Self> {
159        match Self::parse(string) {
160            Ok((remainder, object)) => {
161                // Ensure the remainder is empty.
162                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
163                // Return the object.
164                Ok(object)
165            }
166            Err(error) => bail!("Failed to parse string. {error}"),
167        }
168    }
169}
170
171impl<E: Environment, I: IntegerType> TypeName for Integer<E, I> {
172    /// Returns the type name of the circuit as a string.
173    #[inline]
174    fn type_name() -> &'static str {
175        console::Integer::<E::Network, I>::type_name()
176    }
177}
178
179impl<E: Environment, I: IntegerType> Debug for Integer<E, I> {
180    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181        Display::fmt(self, f)
182    }
183}
184
185impl<E: Environment, I: IntegerType> Display for Integer<E, I> {
186    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187        write!(f, "{}.{}", self.eject_value(), self.eject_mode())
188    }
189}
190
191impl<E: Environment, I: IntegerType> From<Integer<E, I>> for LinearCombination<E::BaseField> {
192    fn from(integer: Integer<E, I>) -> Self {
193        From::from(&integer)
194    }
195}
196
197impl<E: Environment, I: IntegerType> From<&Integer<E, I>> for LinearCombination<E::BaseField> {
198    fn from(integer: &Integer<E, I>) -> Self {
199        // Reconstruct the bits as a linear combination representing the original field value.
200        let mut accumulator = E::zero();
201        let mut coefficient = E::BaseField::one();
202        for bit in &integer.bits_le {
203            accumulator += LinearCombination::from(bit) * coefficient;
204            coefficient = coefficient.double();
205        }
206        accumulator
207    }
208}
209
210#[cfg(test)]
211mod tests {
212    use super::*;
213    use snarkvm_circuit_environment::Circuit;
214
215    const ITERATIONS: u64 = 10;
216
217    fn check_new<I: IntegerType>(
218        mode: Mode,
219        num_constants: u64,
220        num_public: u64,
221        num_private: u64,
222        num_constraints: u64,
223        rng: &mut TestRng,
224    ) {
225        for _ in 0..ITERATIONS {
226            let expected = Uniform::rand(rng);
227
228            Circuit::scope(format!("New {mode}"), || {
229                let candidate = Integer::<Circuit, I>::new(mode, expected);
230                assert_eq!(mode, candidate.eject_mode());
231                assert_eq!(expected, candidate.eject_value());
232                assert_scope!(num_constants, num_public, num_private, num_constraints);
233            })
234        }
235        // Check that the minimum and maximum integer bounds are correct.
236        assert_eq!(console::Integer::MIN, Integer::<Circuit, I>::new(mode, console::Integer::MIN).eject_value());
237        assert_eq!(console::Integer::MAX, Integer::<Circuit, I>::new(mode, console::Integer::MAX).eject_value());
238    }
239
240    fn check_parse<I: IntegerType>(
241        mode: Mode,
242        num_constants: u64,
243        num_public: u64,
244        num_private: u64,
245        num_constraints: u64,
246        rng: &mut TestRng,
247    ) {
248        for _ in 0..ITERATIONS {
249            let value = Uniform::rand(rng);
250            let expected = Integer::<Circuit, I>::new(mode, value);
251
252            Circuit::scope(format!("Parse {mode}"), || {
253                let (_, candidate) = Integer::<Circuit, I>::parse(&format!("{expected}")).unwrap();
254                assert_eq!((mode, value), candidate.eject());
255                assert_eq!(expected.eject_mode(), candidate.eject_mode());
256                assert_eq!(expected.eject_value(), candidate.eject_value());
257                assert_scope!(num_constants, num_public, num_private, num_constraints);
258            })
259        }
260    }
261
262    fn check_display<I: IntegerType>() {
263        // Constant
264        let candidate = Integer::<Circuit, I>::new(Mode::Constant, console::Integer::one() + console::Integer::one());
265        assert_eq!(format!("2{}.constant", I::type_name()), format!("{candidate}"));
266
267        // Public
268        let candidate = Integer::<Circuit, I>::new(Mode::Public, console::Integer::one() + console::Integer::one());
269        assert_eq!(format!("2{}.public", I::type_name()), format!("{candidate}"));
270
271        // Private
272        let candidate = Integer::<Circuit, I>::new(Mode::Private, console::Integer::one() + console::Integer::one());
273        assert_eq!(format!("2{}.private", I::type_name()), format!("{candidate}"));
274    }
275
276    // u8
277
278    #[test]
279    fn test_u8_new() {
280        let mut rng = TestRng::default();
281
282        check_new::<u8>(Mode::Constant, 8, 0, 0, 0, &mut rng);
283        check_new::<u8>(Mode::Public, 0, 8, 0, 8, &mut rng);
284        check_new::<u8>(Mode::Private, 0, 0, 8, 8, &mut rng);
285    }
286
287    #[test]
288    fn test_u8_parse() {
289        let mut rng = TestRng::default();
290
291        check_parse::<u8>(Mode::Constant, 8, 0, 0, 0, &mut rng);
292        check_parse::<u8>(Mode::Public, 0, 8, 0, 8, &mut rng);
293        check_parse::<u8>(Mode::Private, 0, 0, 8, 8, &mut rng);
294    }
295
296    #[test]
297    fn test_u8_display() {
298        check_display::<u8>();
299    }
300
301    // i8
302
303    #[test]
304    fn test_i8_new() {
305        let mut rng = TestRng::default();
306
307        check_new::<i8>(Mode::Constant, 8, 0, 0, 0, &mut rng);
308        check_new::<i8>(Mode::Public, 0, 8, 0, 8, &mut rng);
309        check_new::<i8>(Mode::Private, 0, 0, 8, 8, &mut rng);
310    }
311
312    #[test]
313    fn test_i8_parse() {
314        let mut rng = TestRng::default();
315
316        check_parse::<i8>(Mode::Constant, 8, 0, 0, 0, &mut rng);
317        check_parse::<i8>(Mode::Public, 0, 8, 0, 8, &mut rng);
318        check_parse::<i8>(Mode::Private, 0, 0, 8, 8, &mut rng);
319    }
320
321    #[test]
322    fn test_i8_display() {
323        check_display::<i8>();
324    }
325
326    // u16
327
328    #[test]
329    fn test_u16_new() {
330        let mut rng = TestRng::default();
331
332        check_new::<u16>(Mode::Constant, 16, 0, 0, 0, &mut rng);
333        check_new::<u16>(Mode::Public, 0, 16, 0, 16, &mut rng);
334        check_new::<u16>(Mode::Private, 0, 0, 16, 16, &mut rng);
335    }
336
337    #[test]
338    fn test_u16_parse() {
339        let mut rng = TestRng::default();
340
341        check_parse::<u16>(Mode::Constant, 16, 0, 0, 0, &mut rng);
342        check_parse::<u16>(Mode::Public, 0, 16, 0, 16, &mut rng);
343        check_parse::<u16>(Mode::Private, 0, 0, 16, 16, &mut rng);
344    }
345
346    #[test]
347    fn test_u16_display() {
348        check_display::<u16>();
349    }
350
351    // i16
352
353    #[test]
354    fn test_i16_new() {
355        let mut rng = TestRng::default();
356
357        check_new::<i16>(Mode::Constant, 16, 0, 0, 0, &mut rng);
358        check_new::<i16>(Mode::Public, 0, 16, 0, 16, &mut rng);
359        check_new::<i16>(Mode::Private, 0, 0, 16, 16, &mut rng);
360    }
361
362    #[test]
363    fn test_i16_parse() {
364        let mut rng = TestRng::default();
365
366        check_parse::<i16>(Mode::Constant, 16, 0, 0, 0, &mut rng);
367        check_parse::<i16>(Mode::Public, 0, 16, 0, 16, &mut rng);
368        check_parse::<i16>(Mode::Private, 0, 0, 16, 16, &mut rng);
369    }
370
371    #[test]
372    fn test_i16_display() {
373        check_display::<i16>();
374    }
375
376    // u32
377
378    #[test]
379    fn test_u32_new() {
380        let mut rng = TestRng::default();
381
382        check_new::<u32>(Mode::Constant, 32, 0, 0, 0, &mut rng);
383        check_new::<u32>(Mode::Public, 0, 32, 0, 32, &mut rng);
384        check_new::<u32>(Mode::Private, 0, 0, 32, 32, &mut rng);
385    }
386
387    #[test]
388    fn test_u32_parse() {
389        let mut rng = TestRng::default();
390
391        check_parse::<u32>(Mode::Constant, 32, 0, 0, 0, &mut rng);
392        check_parse::<u32>(Mode::Public, 0, 32, 0, 32, &mut rng);
393        check_parse::<u32>(Mode::Private, 0, 0, 32, 32, &mut rng);
394    }
395
396    #[test]
397    fn test_u32_display() {
398        check_display::<u32>();
399    }
400
401    // i32
402
403    #[test]
404    fn test_i32_new() {
405        let mut rng = TestRng::default();
406
407        check_new::<i32>(Mode::Constant, 32, 0, 0, 0, &mut rng);
408        check_new::<i32>(Mode::Public, 0, 32, 0, 32, &mut rng);
409        check_new::<i32>(Mode::Private, 0, 0, 32, 32, &mut rng);
410    }
411
412    #[test]
413    fn test_i32_parse() {
414        let mut rng = TestRng::default();
415
416        check_parse::<i32>(Mode::Constant, 32, 0, 0, 0, &mut rng);
417        check_parse::<i32>(Mode::Public, 0, 32, 0, 32, &mut rng);
418        check_parse::<i32>(Mode::Private, 0, 0, 32, 32, &mut rng);
419    }
420
421    #[test]
422    fn test_i32_display() {
423        check_display::<i32>();
424    }
425
426    // u64
427
428    #[test]
429    fn test_u64_new() {
430        let mut rng = TestRng::default();
431
432        check_new::<u64>(Mode::Constant, 64, 0, 0, 0, &mut rng);
433        check_new::<u64>(Mode::Public, 0, 64, 0, 64, &mut rng);
434        check_new::<u64>(Mode::Private, 0, 0, 64, 64, &mut rng);
435    }
436
437    #[test]
438    fn test_u64_parse() {
439        let mut rng = TestRng::default();
440
441        check_parse::<u64>(Mode::Constant, 64, 0, 0, 0, &mut rng);
442        check_parse::<u64>(Mode::Public, 0, 64, 0, 64, &mut rng);
443        check_parse::<u64>(Mode::Private, 0, 0, 64, 64, &mut rng);
444    }
445
446    #[test]
447    fn test_u64_display() {
448        check_display::<u64>();
449    }
450
451    // i64
452
453    #[test]
454    fn test_i64_new() {
455        let mut rng = TestRng::default();
456
457        check_new::<i64>(Mode::Constant, 64, 0, 0, 0, &mut rng);
458        check_new::<i64>(Mode::Public, 0, 64, 0, 64, &mut rng);
459        check_new::<i64>(Mode::Private, 0, 0, 64, 64, &mut rng);
460    }
461
462    #[test]
463    fn test_i64_parse() {
464        let mut rng = TestRng::default();
465
466        check_parse::<i64>(Mode::Constant, 64, 0, 0, 0, &mut rng);
467        check_parse::<i64>(Mode::Public, 0, 64, 0, 64, &mut rng);
468        check_parse::<i64>(Mode::Private, 0, 0, 64, 64, &mut rng);
469    }
470
471    #[test]
472    fn test_i64_display() {
473        check_display::<i64>();
474    }
475
476    // u128
477
478    #[test]
479    fn test_u128_new() {
480        let mut rng = TestRng::default();
481
482        check_new::<u128>(Mode::Constant, 128, 0, 0, 0, &mut rng);
483        check_new::<u128>(Mode::Public, 0, 128, 0, 128, &mut rng);
484        check_new::<u128>(Mode::Private, 0, 0, 128, 128, &mut rng);
485    }
486
487    #[test]
488    fn test_u128_parse() {
489        let mut rng = TestRng::default();
490
491        check_parse::<u128>(Mode::Constant, 128, 0, 0, 0, &mut rng);
492        check_parse::<u128>(Mode::Public, 0, 128, 0, 128, &mut rng);
493        check_parse::<u128>(Mode::Private, 0, 0, 128, 128, &mut rng);
494    }
495
496    #[test]
497    fn test_u128_display() {
498        check_display::<u128>();
499    }
500
501    // i128
502
503    #[test]
504    fn test_i128_new() {
505        let mut rng = TestRng::default();
506
507        check_new::<i128>(Mode::Constant, 128, 0, 0, 0, &mut rng);
508        check_new::<i128>(Mode::Public, 0, 128, 0, 128, &mut rng);
509        check_new::<i128>(Mode::Private, 0, 0, 128, 128, &mut rng);
510    }
511
512    #[test]
513    fn test_i128_parse() {
514        let mut rng = TestRng::default();
515
516        check_parse::<i128>(Mode::Constant, 128, 0, 0, 0, &mut rng);
517        check_parse::<i128>(Mode::Public, 0, 128, 0, 128, &mut rng);
518        check_parse::<i128>(Mode::Private, 0, 0, 128, 128, &mut rng);
519    }
520
521    #[test]
522    fn test_i128_display() {
523        check_display::<i128>();
524    }
525}
526
527#[cfg(test)]
528mod test_utilities {
529    use core::panic::UnwindSafe;
530
531    /// A generic template for an integer test case.
532    #[macro_export]
533    macro_rules! test_integer_case {
534        // Typical test instantiation (static).
535        ($test_fn:ident, $primitive:ident, $description:ident) => {
536            paste::paste! {
537                #[test]
538                fn [<test_ $primitive _ $description>]() {
539                    $test_fn::<$primitive>();
540                }
541            }
542        };
543        // Typical test instantiation (unary).
544        ($test_fn:ident, $primitive:ident, $mode:expr, $description:ident) => {
545            paste::paste! {
546                #[test]
547                fn [<test_ $primitive _ $description>]() {
548                    $test_fn::<$primitive>($mode);
549                }
550            }
551        };
552        // Typical test instantiation (binary).
553        ($test_fn:ident, $primitive:ident, $mode_a:expr, $mode_b:expr, $description:ident) => {
554            paste::paste! {
555                #[test]
556                fn [<test_ $primitive _ $description>]() {
557                    $test_fn::<$primitive>($mode_a, $mode_b);
558                }
559            }
560        };
561        // Typical test instantiation (binary).
562        ($test_fn:ident, $primitive_a:ident, $primitive_b:ident, $mode_a:expr, $mode_b:expr, $description:ident) => {
563            paste::paste! {
564                #[test]
565                fn [<test_ $primitive_a _ $description _ $primitive_b>]() {
566                    $test_fn::<$primitive_a, $primitive_b>($mode_a, $mode_b);
567                }
568            }
569        };
570        // Typical test instantiation (ternary).
571        ($test_fn:ident, $primitive:ident, $mode_a:expr, $mode_b:expr, $mode_c:expr, $description:ident) => {
572            paste::paste! {
573                #[test]
574                fn [<test_ $primitive _ $description>]() {
575                    $test_fn::<$primitive>($mode_a, $mode_b, $mode_c);
576                }
577            }
578        };
579        // Typically used to ignore exhaustive tests by default (unary).
580        (#[$meta:meta], $test_fn:ident, $primitive:ident, $mode:expr, $description:ident) => {
581            paste::paste! {
582                #[test]
583                #[$meta]
584                fn [<test_ $primitive _ $description>]() {
585                    $test_fn::<$primitive>($mode);
586                }
587            }
588        };
589        // Typically used to ignore exhaustive tests by default (binary).
590        (#[$meta:meta], $test_fn:ident, $primitive:ident, $mode_a:expr, $mode_b:expr, $description:ident) => {
591            paste::paste! {
592                #[test]
593                #[$meta]
594                fn [<test_ $primitive _ $description>]() {
595                    $test_fn::<$primitive>($mode_a, $mode_b);
596                }
597            }
598        };
599        // Typically used to ignore exhaustive tests by default (binary).
600        (#[$meta:meta], $test_fn:ident, $primitive_a:ident, $primitive_b:ident, $mode_a:expr, $mode_b:expr, $description:ident) => {
601            paste::paste! {
602                #[test]
603                #[$meta]
604                fn [<test_ $primitive_a _ $description _ $primitive_b>]() {
605                    $test_fn::<$primitive_a, $primitive_b>($mode_a, $mode_b);
606                }
607            }
608        };
609        // Typically used to ignore exhaustive tests by default (ternary).
610        (#[$meta:meta], $test_fn:ident, $primitive:ident, $mode_a:expr, $mode_b:expr, $mode_c:expr, $description:ident) => {
611            paste::paste! {
612                #[test]
613                #[$meta]
614                fn [<test_ $primitive _ $description>]() {
615                    $test_fn::<$primitive>($mode_a, $mode_b, $mode_c);
616                }
617            }
618        };
619    }
620
621    /// Invokes `test_integer_case!` on all combinations of `Mode`s.
622    #[macro_export]
623    macro_rules! test_integer_static {
624        ($test_fn:ident, $primitive:ident, $description:ident) => {
625            test_integer_case!($test_fn, $primitive, $description);
626        };
627    }
628
629    /// Invokes `test_integer_case!` on all combinations of `Mode`s.
630    #[macro_export]
631    macro_rules! test_integer_unary {
632        ($test_fn:ident, $primitive:ident, $description:ident) => {
633            paste::paste! {
634                test_integer_case!($test_fn, $primitive, Mode::Constant, [<$description _ constant>]);
635                test_integer_case!($test_fn, $primitive, Mode::Public, [<$description _ public>]);
636                test_integer_case!($test_fn, $primitive, Mode::Private, [<$description _ private>]);
637            }
638        };
639        (#[$meta:meta], $test_fn:ident, $primitive:ident, $description:ident, $variant:ident) => {
640            paste::paste! {
641                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Constant, [<$description _ constant _ $variant>]);
642                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Public, [<$description _ public _ $variant>]);
643                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Private, [<$description _ private _ $variant>]);
644            }
645        };
646    }
647
648    /// Invokes `test_integer_case!` on all combinations of `Mode`s.
649    #[macro_export]
650    macro_rules! test_integer_binary {
651        ($test_fn:ident, $primitive:ident, $description:ident) => {
652            paste::paste! {
653                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Constant, [<constant _ $description _ constant>]);
654                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Public, [<constant _ $description _ public>]);
655                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Private, [<constant _ $description _ private>]);
656                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Constant, [<public _ $description _ constant>]);
657                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Public, [<public _ $description _ public>]);
658                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Private, [<public _ $description _ private>]);
659                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Constant, [<private _ $description _ constant>]);
660                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Public, [<private _ $description _ public>]);
661                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Private, [<private _ $description _ private>]);
662            }
663        };
664        ($test_fn:ident, $primitive_a:ident, $primitive_b:ident, $description:ident) => {
665            paste::paste! {
666                test_integer_case!($test_fn, $primitive_a, $primitive_b, Mode::Constant, Mode::Constant, [<constant _ $description _ constant>]);
667                test_integer_case!($test_fn, $primitive_a, $primitive_b, Mode::Constant, Mode::Public, [<constant _ $description _ public>]);
668                test_integer_case!($test_fn, $primitive_a, $primitive_b, Mode::Constant, Mode::Private, [<constant _ $description _ private>]);
669                test_integer_case!($test_fn, $primitive_a, $primitive_b, Mode::Public, Mode::Constant, [<public _ $description _ constant>]);
670                test_integer_case!($test_fn, $primitive_a, $primitive_b, Mode::Public, Mode::Public, [<public _ $description _ public>]);
671                test_integer_case!($test_fn, $primitive_a, $primitive_b, Mode::Public, Mode::Private, [<public _ $description _ private>]);
672                test_integer_case!($test_fn, $primitive_a, $primitive_b, Mode::Private, Mode::Constant, [<private _ $description _ constant>]);
673                test_integer_case!($test_fn, $primitive_a, $primitive_b, Mode::Private, Mode::Public, [<private _ $description _ public>]);
674                test_integer_case!($test_fn, $primitive_a, $primitive_b, Mode::Private, Mode::Private, [<private _ $description _ private>]);
675            }
676        };
677        (#[$meta:meta], $test_fn:ident, $primitive:ident, $description:ident, $variant:ident) => {
678            paste::paste! {
679                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Constant, Mode::Constant, [<constant _ $description _ constant _ $variant>]);
680                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Constant, Mode::Public, [<constant _ $description _ public _ $variant>]);
681                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Constant, Mode::Private, [<constant _ $description _ private _ $variant>]);
682                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Public, Mode::Constant, [<public _ $description _ constant _ $variant>]);
683                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Public, Mode::Public, [<public _ $description _ public _ $variant>]);
684                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Public, Mode::Private, [<public _ $description _ private _ $variant>]);
685                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Private, Mode::Constant, [<private _ $description _ constant _ $variant>]);
686                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Private, Mode::Public, [<private _ $description _ public _ $variant>]);
687                test_integer_case!(#[$meta], $test_fn, $primitive, Mode::Private, Mode::Private, [<private _ $description _ private _ $variant>]);
688            }
689        };
690        (#[$meta:meta], $test_fn:ident, $primitive_a:ident, $primitive_b:ident, $description:ident, $variant:ident) => {
691            paste::paste! {
692                test_integer_case!(#[$meta], $test_fn, $primitive_a, $primitive_b, Mode::Constant, Mode::Constant, [<constant _ $description _ constant _ $variant>]);
693                test_integer_case!(#[$meta], $test_fn, $primitive_a, $primitive_b, Mode::Constant, Mode::Public, [<constant _ $description _ public _ $variant>]);
694                test_integer_case!(#[$meta], $test_fn, $primitive_a, $primitive_b, Mode::Constant, Mode::Private, [<constant _ $description _ private _ $variant>]);
695                test_integer_case!(#[$meta], $test_fn, $primitive_a, $primitive_b, Mode::Public, Mode::Constant, [<public _ $description _ constant _ $variant>]);
696                test_integer_case!(#[$meta], $test_fn, $primitive_a, $primitive_b, Mode::Public, Mode::Public, [<public _ $description _ public _ $variant>]);
697                test_integer_case!(#[$meta], $test_fn, $primitive_a, $primitive_b, Mode::Public, Mode::Private, [<public _ $description _ private _ $variant>]);
698                test_integer_case!(#[$meta], $test_fn, $primitive_a, $primitive_b, Mode::Private, Mode::Constant, [<private _ $description _ constant _ $variant>]);
699                test_integer_case!(#[$meta], $test_fn, $primitive_a, $primitive_b, Mode::Private, Mode::Public, [<private _ $description _ public _ $variant>]);
700                test_integer_case!(#[$meta], $test_fn, $primitive_a, $primitive_b, Mode::Private, Mode::Private, [<private _ $description _ private _ $variant>]);
701            }
702        };
703    }
704
705    /// Invokes `test_integer_case!` on all combinations of `Mode`s.
706    #[macro_export]
707    macro_rules! test_integer_ternary {
708        ($test_fn:ident, $primitive:ident, $description_a:ident, $description_b:ident, $description_c:ident) => {
709            paste::paste! {
710                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Constant, Mode::Constant, [<$description_a _ constant _ $description_b _ constant _ $description_c _ constant>]);
711                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Constant, Mode::Public, [<$description_a _ constant _ $description_b _ constant _ $description_c _ public>]);
712                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Constant, Mode::Private, [<$description_a _ constant _ $description_b _ constant _ $description_c _ private>]);
713                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Public, Mode::Constant, [<$description_a _ constant _ $description_b _ public _ $description_c _ constant>]);
714                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Public, Mode::Public, [<$description_a _ constant _ $description_b _ public _ $description_c _ public>]);
715                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Public, Mode::Private, [<$description_a _ constant _ $description_b _ public _ $description_c _ private>]);
716                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Private, Mode::Constant, [<$description_a _ constant _ $description_b _ private _ $description_c _ constant>]);
717                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Private, Mode::Public, [<$description_a _ constant _ $description_b _ private _ $description_c _ public>]);
718                test_integer_case!($test_fn, $primitive, Mode::Constant, Mode::Private, Mode::Private, [<$description_a _ constant _ $description_b _ private _ $description_c _ private>]);
719                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Constant, Mode::Constant, [<$description_a _ public _ $description_b _ constant _ $description_c _ constant>]);
720                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Constant, Mode::Public, [<$description_a _ public _ $description_b _ constant _ $description_c _ public>]);
721                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Constant, Mode::Private, [<$description_a _ public _ $description_b _ constant _ $description_c _ private>]);
722                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Public, Mode::Constant, [<$description_a _ public _ $description_b _ public _ $description_c _ constant>]);
723                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Public, Mode::Public, [<$description_a _ public _ $description_b _ public _ $description_c _ public>]);
724                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Public, Mode::Private, [<$description_a _ public _ $description_b _ public _ $description_c _ private>]);
725                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Private, Mode::Constant, [<$description_a _ public _ $description_b _ private _ $description_c _ constant>]);
726                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Private, Mode::Public, [<$description_a _ public _ $description_b _ private _ $description_c _ public>]);
727                test_integer_case!($test_fn, $primitive, Mode::Public, Mode::Private, Mode::Private, [<$description_a _ public _ $description_b _ private _ $description_c _ private>]);
728                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Constant, Mode::Constant, [<$description_a _ private _ $description_b _ constant _ $description_c _ constant>]);
729                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Constant, Mode::Public, [<$description_a _ private _ $description_b _ constant _ $description_c _ public>]);
730                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Constant, Mode::Private, [<$description_a _ private _ $description_b _ constant _ $description_c _ private>]);
731                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Public, Mode::Constant, [<$description_a _ private _ $description_b _ public _ $description_c _ constant>]);
732                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Public, Mode::Public, [<$description_a _ private _ $description_b _ public _ $description_c _ public>]);
733                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Public, Mode::Private, [<$description_a _ private _ $description_b _ public _ $description_c _ private>]);
734                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Private, Mode::Constant, [<$description_a _ private _ $description_b _ private _ $description_c _ constant>]);
735                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Private, Mode::Public, [<$description_a _ private _ $description_b _ private _ $description_c _ public>]);
736                test_integer_case!($test_fn, $primitive, Mode::Private, Mode::Private, Mode::Private, [<$description_a _ private _ $description_b _ private _ $description_c _ private>]);
737            }
738        };
739    }
740
741    pub fn check_operation_halts<LHS: UnwindSafe, RHS: UnwindSafe, OUT>(
742        a: LHS,
743        b: RHS,
744        operation: impl FnOnce(LHS, RHS) -> OUT + UnwindSafe,
745    ) {
746        let result = std::panic::catch_unwind(|| operation(a, b));
747        assert!(result.is_err());
748    }
749
750    pub fn check_unary_operation_halts<IN: UnwindSafe, OUT>(input: IN, operation: impl FnOnce(IN) -> OUT + UnwindSafe) {
751        let result = std::panic::catch_unwind(|| operation(input));
752        assert!(result.is_err());
753    }
754}