1use crate::Choice;
2use core::{
3 cmp,
4 num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize},
5};
6
7pub trait CtLt {
9 #[must_use]
11 fn ct_lt(&self, other: &Self) -> Choice;
12}
13
14macro_rules! impl_unsigned_ct_lt {
16 ( $($uint:ty),+ ) => {
17 $(
18 impl CtLt for $uint {
19 #[inline]
20 fn ct_lt(&self, other: &Self) -> Choice {
21 let (_, overflow) = self.overflowing_sub(*other);
22 Choice(overflow.into())
23 }
24 }
25 )+
26 };
27}
28
29impl_unsigned_ct_lt!(u8, u16, u32, u64, u128, usize);
30
31macro_rules! impl_ct_lt_for_nonzero_integer {
33 ( $($ty:ty),+ ) => {
34 $(
35 impl CtLt for $ty {
36 #[inline]
37 fn ct_lt(&self, other: &Self) -> Choice {
38 self.get().ct_lt(&other.get())
39 }
40 }
41 )+
42 };
43}
44
45impl_ct_lt_for_nonzero_integer!(
46 NonZeroU8,
47 NonZeroU16,
48 NonZeroU32,
49 NonZeroU64,
50 NonZeroU128,
51 NonZeroUsize
52);
53
54impl CtLt for cmp::Ordering {
55 #[inline]
56 #[allow(clippy::arithmetic_side_effects, clippy::cast_sign_loss)]
57 fn ct_lt(&self, other: &Self) -> Choice {
58 let a = (*self as i8) + 1;
61 let b = (*other as i8) + 1;
62
63 (a as u8).ct_lt(&(b as u8))
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::CtLt;
71 use core::cmp::Ordering;
72
73 #[test]
74 fn ct_lt() {
75 let a = 42u64;
76 let b = 43u64;
77 assert!(!a.ct_lt(&a).to_bool());
78 assert!(a.ct_lt(&b).to_bool());
79 assert!(!b.ct_lt(&a).to_bool());
80 }
81
82 macro_rules! ct_lt_tests {
84 ( $($int:ident),+ ) => {
85 $(
86 mod $int {
87 use super::CtLt;
88
89 #[test]
90 fn ct_gt() {
91 let a = <$int>::MIN;
92 let b = <$int>::MAX;
93 assert!(!a.ct_lt(&a).to_bool());
94 assert!(a.ct_lt(&b).to_bool());
95 assert!(!b.ct_lt(&a).to_bool());
96 }
97
98 }
99 )+
100 };
101 }
102
103 ct_lt_tests!(u8, u16, u32, u64, u128, usize);
104
105 #[test]
106 fn ordering() {
107 assert!(!Ordering::Equal.ct_lt(&Ordering::Equal).to_bool());
108 assert!(Ordering::Less.ct_lt(&Ordering::Greater).to_bool());
109 assert!(!Ordering::Greater.ct_lt(&Ordering::Less).to_bool());
110 }
111}