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 {
12 #[must_use]
15 fn ct_neg(&self, choice: Choice) -> Self;
16
17 fn ct_neg_assign(&mut self, choice: Choice) {
20 *self = self.ct_neg(choice);
21 }
22}
23
24macro_rules! impl_signed_ct_neg {
26 ( $($int:ty),+ ) => {
27 $(
28 impl CtNeg for $int {
29 #[inline]
30 fn ct_neg(&self, choice: Choice) -> Self {
31 self.ct_select(&self.wrapping_neg(), choice)
32 }
33
34 #[inline]
35 fn ct_neg_assign(&mut self, choice: Choice) {
36 self.ct_assign(&self.wrapping_neg(), choice)
37 }
38 }
39 )+
40 };
41}
42
43macro_rules! impl_unsigned_ct_neg {
45 ( $($uint:ty),+ ) => {
46 $(
47 impl CtNeg for $uint {
48 #[inline]
49 fn ct_neg(&self, choice: Choice) -> Self {
50 self.ct_select(&self.wrapping_neg(), choice)
51 }
52
53 #[inline]
54 fn ct_neg_assign(&mut self, choice: Choice) {
55 self.ct_assign(&self.wrapping_neg(), choice)
56 }
57 }
58 )+
59 };
60}
61
62impl_signed_ct_neg!(
63 i8,
64 i16,
65 i32,
66 i64,
67 i128,
68 isize,
69 NonZeroI8,
70 NonZeroI16,
71 NonZeroI32,
72 NonZeroI64,
73 NonZeroI128,
74 NonZeroIsize
75);
76impl_unsigned_ct_neg!(u8, u16, u32, u64, u128, usize);
77
78macro_rules! impl_ct_neg_for_unsigned_nonzero {
83 ( $($nzuint:ident),+ ) => {
84 $(
85 impl CtNeg for $nzuint {
86 #[inline]
87 fn ct_neg(&self, choice: Choice) -> Self {
88 let n = self.get().ct_select(&self.get().wrapping_neg(), choice);
90 $nzuint::new(n).expect("should be non-zero")
91 }
92 }
93 )+
94 };
95}
96
97impl_ct_neg_for_unsigned_nonzero!(
98 NonZeroU8,
99 NonZeroU16,
100 NonZeroU32,
101 NonZeroU64,
102 NonZeroU128,
103 NonZeroUsize
104);
105
106#[cfg(test)]
107mod tests {
108 macro_rules! signed_ct_neg_tests {
110 ( $($int:ident),+ ) => {
111 $(
112 mod $int {
113 use crate::{Choice, CtNeg};
114
115 #[test]
116 fn ct_neg() {
117 let n: $int = 42;
118 assert_eq!(n, n.ct_neg(Choice::FALSE));
119 assert_eq!(-n, n.ct_neg(Choice::TRUE));
120 }
121
122 #[test]
123 fn ct_neg_assign() {
124 let n: $int = 42;
125 let mut x = n;
126 x.ct_neg_assign(Choice::FALSE);
127 assert_eq!(n, x);
128
129 x.ct_neg_assign(Choice::TRUE);
130 assert_eq!(-n, x);
131 }
132
133 #[test]
134 fn ct_neg_min() {
135 let min = <$int>::MIN;
136 for choice in [Choice::FALSE, Choice::TRUE] {
137 assert_eq!(min.ct_neg(choice), min);
138 let mut value = min;
139 value.ct_neg_assign(choice);
140 assert_eq!(value, min);
141 }
142 }
143 }
144 )+
145 };
146 }
147
148 macro_rules! unsigned_ct_neg_tests {
150 ( $($uint:ident),+ ) => {
151 $(
152 mod $uint {
153 use crate::{Choice, CtNeg};
154
155 #[test]
156 fn ct_neg() {
157 let n: $uint = 42;
158 assert_eq!(n, n.ct_neg(Choice::FALSE));
159 assert_eq!(<$uint>::MAX - n + 1, n.ct_neg(Choice::TRUE));
160 }
161
162 #[test]
163 fn ct_neg_assign() {
164 let n: $uint = 42;
165 let mut x = n;
166 x.ct_neg_assign(Choice::FALSE);
167 assert_eq!(n, x);
168
169 x.ct_neg_assign(Choice::TRUE);
170 assert_eq!(<$uint>::MAX - n + 1, x);
171 }
172 }
173 )+
174 };
175 }
176
177 signed_ct_neg_tests!(i8, i16, i32, i64, i128, isize);
178 unsigned_ct_neg_tests!(u8, u16, u32, u64, u128, usize);
179
180 macro_rules! nonzero_signed_ct_neg_tests {
181 ($(($test:ident, $ty:ty, $int:ty)),+ $(,)?) => {
182 $(
183 #[test]
184 fn $test() {
185 use crate::{Choice, CtNeg};
186 let min = <$ty>::new(<$int>::MIN).expect("MIN is non-zero");
187 for choice in [Choice::FALSE, Choice::TRUE] {
188 assert_eq!(min.ct_neg(choice), min);
189 let mut value = min;
190 value.ct_neg_assign(choice);
191 assert_eq!(value, min);
192 }
193 }
194 )+
195 };
196 }
197
198 nonzero_signed_ct_neg_tests!(
199 (nonzero_i8_min, core::num::NonZeroI8, i8),
200 (nonzero_i16_min, core::num::NonZeroI16, i16),
201 (nonzero_i32_min, core::num::NonZeroI32, i32),
202 (nonzero_i64_min, core::num::NonZeroI64, i64),
203 (nonzero_i128_min, core::num::NonZeroI128, i128),
204 (nonzero_isize_min, core::num::NonZeroIsize, isize),
205 );
206}