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, usize);
30
31impl CtLt for u128 {
32 #[inline]
33 fn ct_lt(&self, other: &Self) -> Choice {
34 Choice::from_u128_lt(*self, *other)
35 }
36}
37
38macro_rules! impl_ct_lt_for_nonzero_integer {
40 ( $($ty:ty),+ ) => {
41 $(
42 impl CtLt for $ty {
43 #[inline]
44 fn ct_lt(&self, other: &Self) -> Choice {
45 self.get().ct_lt(&other.get())
46 }
47 }
48 )+
49 };
50}
51
52impl_ct_lt_for_nonzero_integer!(
53 NonZeroU8,
54 NonZeroU16,
55 NonZeroU32,
56 NonZeroU64,
57 NonZeroU128,
58 NonZeroUsize
59);
60
61impl CtLt for cmp::Ordering {
62 #[inline]
63 #[allow(clippy::arithmetic_side_effects, clippy::cast_sign_loss)]
64 fn ct_lt(&self, other: &Self) -> Choice {
65 let a = (*self as i8) + 1;
66 let b = (*other as i8) + 1;
67
68 a.cast_unsigned().ct_lt(&b.cast_unsigned())
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::CtLt;
76 use core::cmp::Ordering;
77
78 #[test]
79 fn ct_lt() {
80 let a = 42u64;
81 let b = 43u64;
82 assert!(!a.ct_lt(&a).to_bool());
83 assert!(a.ct_lt(&b).to_bool());
84 assert!(!b.ct_lt(&a).to_bool());
85 }
86
87 macro_rules! ct_lt_tests {
89 ( $($int:ident),+ ) => {
90 $(
91 mod $int {
92 use super::CtLt;
93
94 #[test]
95 fn ct_gt() {
96 let a = <$int>::MIN;
97 let b = <$int>::MAX;
98 assert!(!a.ct_lt(&a).to_bool());
99 assert!(a.ct_lt(&b).to_bool());
100 assert!(!b.ct_lt(&a).to_bool());
101 }
102
103 }
104 )+
105 };
106 }
107
108 ct_lt_tests!(u8, u16, u32, u64, u128, usize);
109
110 #[test]
111 fn ordering() {
112 assert!(!Ordering::Equal.ct_lt(&Ordering::Equal).to_bool());
113 assert!(Ordering::Less.ct_lt(&Ordering::Greater).to_bool());
114 assert!(!Ordering::Greater.ct_lt(&Ordering::Less).to_bool());
115 }
116}