use crate::{Choice, CtAssign, CtSelect};
use core::num::{
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
};
pub trait CtNeg: Sized {
#[must_use]
fn ct_neg(&self, choice: Choice) -> Self;
fn ct_neg_assign(&mut self, choice: Choice) {
*self = self.ct_neg(choice);
}
}
macro_rules! impl_signed_ct_neg {
( $($int:ty),+ ) => {
$(
impl CtNeg for $int {
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn ct_neg(&self, choice: Choice) -> Self {
self.ct_select(&-*self, choice)
}
#[inline]
#[allow(clippy::arithmetic_side_effects)]
fn ct_neg_assign(&mut self, choice: Choice) {
self.ct_assign(&-*self, choice)
}
}
)+
};
}
macro_rules! impl_unsigned_ct_neg {
( $($uint:ty),+ ) => {
$(
impl CtNeg for $uint {
#[inline]
fn ct_neg(&self, choice: Choice) -> Self {
self.ct_select(&self.wrapping_neg(), choice)
}
#[inline]
fn ct_neg_assign(&mut self, choice: Choice) {
self.ct_assign(&self.wrapping_neg(), choice)
}
}
)+
};
}
impl_signed_ct_neg!(
i8,
i16,
i32,
i64,
i128,
isize,
NonZeroI8,
NonZeroI16,
NonZeroI32,
NonZeroI64,
NonZeroI128,
NonZeroIsize
);
impl_unsigned_ct_neg!(u8, u16, u32, u64, u128, usize);
macro_rules! impl_ct_neg_for_unsigned_nonzero {
( $($nzuint:ident),+ ) => {
$(
impl CtNeg for $nzuint {
#[inline]
fn ct_neg(&self, choice: Choice) -> Self {
let n = self.get().ct_select(&self.get().wrapping_neg(), choice);
$nzuint::new(n).expect("should be non-zero")
}
}
)+
};
}
impl_ct_neg_for_unsigned_nonzero!(
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU128,
NonZeroUsize
);
#[cfg(test)]
mod tests {
macro_rules! signed_ct_neg_tests {
( $($int:ident),+ ) => {
$(
mod $int {
use crate::{Choice, CtNeg};
#[test]
fn ct_neg() {
let n: $int = 42;
assert_eq!(n, n.ct_neg(Choice::FALSE));
assert_eq!(-n, n.ct_neg(Choice::TRUE));
}
#[test]
fn ct_neg_assign() {
let n: $int = 42;
let mut x = n;
x.ct_neg_assign(Choice::FALSE);
assert_eq!(n, x);
x.ct_neg_assign(Choice::TRUE);
assert_eq!(-n, x);
}
}
)+
};
}
macro_rules! unsigned_ct_neg_tests {
( $($uint:ident),+ ) => {
$(
mod $uint {
use crate::{Choice, CtNeg};
#[test]
fn ct_neg() {
let n: $uint = 42;
assert_eq!(n, n.ct_neg(Choice::FALSE));
assert_eq!(<$uint>::MAX - n + 1, n.ct_neg(Choice::TRUE));
}
#[test]
fn ct_neg_assign() {
let n: $uint = 42;
let mut x = n;
x.ct_neg_assign(Choice::FALSE);
assert_eq!(n, x);
x.ct_neg_assign(Choice::TRUE);
assert_eq!(<$uint>::MAX - n + 1, x);
}
}
)+
};
}
signed_ct_neg_tests!(i8, i16, i32, i64, i128, isize);
unsigned_ct_neg_tests!(u8, u16, u32, u64, u128, usize);
}