1use crate::{Choice, CtAssign, CtSelect};
2use core::num::{
3 NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
4 NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
5};
6
7pub trait CtNeg: Sized {
9 #[must_use]
12 fn ct_neg(&self, choice: Choice) -> Self;
13
14 fn ct_neg_assign(&mut self, choice: Choice) {
17 *self = self.ct_neg(choice);
18 }
19}
20
21macro_rules! impl_signed_ct_neg {
23 ( $($int:ty),+ ) => {
24 $(
25 impl CtNeg for $int {
26 #[inline]
27 #[allow(clippy::arithmetic_side_effects)]
28 fn ct_neg(&self, choice: Choice) -> Self {
29 self.ct_select(&-*self, choice)
30 }
31
32 #[inline]
33 #[allow(clippy::arithmetic_side_effects)]
34 fn ct_neg_assign(&mut self, choice: Choice) {
35 self.ct_assign(&-*self, choice)
36 }
37 }
38 )+
39 };
40}
41
42macro_rules! impl_unsigned_ct_neg {
44 ( $($uint:ty),+ ) => {
45 $(
46 impl CtNeg for $uint {
47 #[inline]
48 fn ct_neg(&self, choice: Choice) -> Self {
49 self.ct_select(&self.wrapping_neg(), choice)
50 }
51
52 #[inline]
53 fn ct_neg_assign(&mut self, choice: Choice) {
54 self.ct_assign(&self.wrapping_neg(), choice)
55 }
56 }
57 )+
58 };
59}
60
61impl_signed_ct_neg!(
62 i8,
63 i16,
64 i32,
65 i64,
66 i128,
67 isize,
68 NonZeroI8,
69 NonZeroI16,
70 NonZeroI32,
71 NonZeroI64,
72 NonZeroI128,
73 NonZeroIsize
74);
75impl_unsigned_ct_neg!(u8, u16, u32, u64, u128, usize);
76
77macro_rules! impl_ct_neg_for_unsigned_nonzero {
82 ( $($nzuint:ident),+ ) => {
83 $(
84 impl CtNeg for $nzuint {
85 #[inline]
86 fn ct_neg(&self, choice: Choice) -> Self {
87 let n = self.get().ct_select(&self.get().wrapping_neg(), choice);
89 $nzuint::new(n).expect("should be non-zero")
90 }
91 }
92 )+
93 };
94}
95
96impl_ct_neg_for_unsigned_nonzero!(
97 NonZeroU8,
98 NonZeroU16,
99 NonZeroU32,
100 NonZeroU64,
101 NonZeroU128,
102 NonZeroUsize
103);
104
105#[cfg(test)]
106mod tests {
107 macro_rules! signed_ct_neg_tests {
109 ( $($int:ident),+ ) => {
110 $(
111 mod $int {
112 use crate::{Choice, CtNeg};
113
114 #[test]
115 fn ct_neg() {
116 let n: $int = 42;
117 assert_eq!(n, n.ct_neg(Choice::FALSE));
118 assert_eq!(-n, n.ct_neg(Choice::TRUE));
119 }
120
121 #[test]
122 fn ct_neg_assign() {
123 let n: $int = 42;
124 let mut x = n;
125 x.ct_neg_assign(Choice::FALSE);
126 assert_eq!(n, x);
127
128 x.ct_neg_assign(Choice::TRUE);
129 assert_eq!(-n, x);
130 }
131 }
132 )+
133 };
134 }
135
136 macro_rules! unsigned_ct_neg_tests {
138 ( $($uint:ident),+ ) => {
139 $(
140 mod $uint {
141 use crate::{Choice, CtNeg};
142
143 #[test]
144 fn ct_neg() {
145 let n: $uint = 42;
146 assert_eq!(n, n.ct_neg(Choice::FALSE));
147 assert_eq!(<$uint>::MAX - n + 1, n.ct_neg(Choice::TRUE));
148 }
149
150 #[test]
151 fn ct_neg_assign() {
152 let n: $uint = 42;
153 let mut x = n;
154 x.ct_neg_assign(Choice::FALSE);
155 assert_eq!(n, x);
156
157 x.ct_neg_assign(Choice::TRUE);
158 assert_eq!(<$uint>::MAX - n + 1, x);
159 }
160 }
161 )+
162 };
163 }
164
165 signed_ct_neg_tests!(i8, i16, i32, i64, i128, isize);
166 unsigned_ct_neg_tests!(u8, u16, u32, u64, u128, usize);
167}