1use core::{cmp, fmt, ops};
2
3pub trait MinInt:
5    Copy
6    + fmt::Debug
7    + ops::BitOr<Output = Self>
8    + ops::Not<Output = Self>
9    + ops::Shl<u32, Output = Self>
10{
11    type OtherSign: MinInt;
13    type Unsigned: MinInt;
15
16    const SIGNED: bool;
18
19    const BITS: u32;
21
22    const ZERO: Self;
23    const ONE: Self;
24    const MIN: Self;
25    const MAX: Self;
26}
27
28pub type OtherSign<I> = <I as MinInt>::OtherSign;
31
32#[allow(dead_code)]
34pub trait Int:
35    MinInt
36    + fmt::Display
37    + fmt::Binary
38    + fmt::LowerHex
39    + PartialEq
40    + PartialOrd
41    + ops::AddAssign
42    + ops::SubAssign
43    + ops::MulAssign
44    + ops::DivAssign
45    + ops::RemAssign
46    + ops::BitAndAssign
47    + ops::BitOrAssign
48    + ops::BitXorAssign
49    + ops::ShlAssign<i32>
50    + ops::ShlAssign<u32>
51    + ops::ShrAssign<u32>
52    + ops::ShrAssign<i32>
53    + ops::Add<Output = Self>
54    + ops::Sub<Output = Self>
55    + ops::Mul<Output = Self>
56    + ops::Div<Output = Self>
57    + ops::Rem<Output = Self>
58    + ops::Shl<i32, Output = Self>
59    + ops::Shl<u32, Output = Self>
60    + ops::Shr<i32, Output = Self>
61    + ops::Shr<u32, Output = Self>
62    + ops::BitXor<Output = Self>
63    + ops::BitAnd<Output = Self>
64    + cmp::Ord
65    + From<bool>
66    + CastFrom<i32>
67    + CastFrom<u16>
68    + CastFrom<u32>
69    + CastFrom<u8>
70    + CastFrom<usize>
71    + CastInto<i32>
72    + CastInto<u16>
73    + CastInto<u32>
74    + CastInto<u8>
75    + CastInto<usize>
76{
77    fn signed(self) -> OtherSign<Self::Unsigned>;
78    fn unsigned(self) -> Self::Unsigned;
79    fn from_unsigned(unsigned: Self::Unsigned) -> Self;
80    fn abs(self) -> Self;
81
82    fn from_bool(b: bool) -> Self;
83
84    fn logical_shr(self, other: u32) -> Self;
86
87    fn abs_diff(self, other: Self) -> Self::Unsigned;
89
90    fn is_zero(self) -> bool;
92    fn checked_add(self, other: Self) -> Option<Self>;
93    fn checked_sub(self, other: Self) -> Option<Self>;
94    fn wrapping_neg(self) -> Self;
95    fn wrapping_add(self, other: Self) -> Self;
96    fn wrapping_mul(self, other: Self) -> Self;
97    fn wrapping_sub(self, other: Self) -> Self;
98    fn wrapping_shl(self, other: u32) -> Self;
99    fn wrapping_shr(self, other: u32) -> Self;
100    fn rotate_left(self, other: u32) -> Self;
101    fn overflowing_add(self, other: Self) -> (Self, bool);
102    fn overflowing_sub(self, other: Self) -> (Self, bool);
103    fn leading_zeros(self) -> u32;
104    fn ilog2(self) -> u32;
105}
106
107macro_rules! int_impl_common {
108    ($ty:ty) => {
109        fn from_bool(b: bool) -> Self {
110            b as $ty
111        }
112
113        fn logical_shr(self, other: u32) -> Self {
114            Self::from_unsigned(self.unsigned().wrapping_shr(other))
115        }
116
117        fn is_zero(self) -> bool {
118            self == Self::ZERO
119        }
120
121        fn checked_add(self, other: Self) -> Option<Self> {
122            self.checked_add(other)
123        }
124
125        fn checked_sub(self, other: Self) -> Option<Self> {
126            self.checked_sub(other)
127        }
128
129        fn wrapping_neg(self) -> Self {
130            <Self>::wrapping_neg(self)
131        }
132
133        fn wrapping_add(self, other: Self) -> Self {
134            <Self>::wrapping_add(self, other)
135        }
136
137        fn wrapping_mul(self, other: Self) -> Self {
138            <Self>::wrapping_mul(self, other)
139        }
140
141        fn wrapping_sub(self, other: Self) -> Self {
142            <Self>::wrapping_sub(self, other)
143        }
144
145        fn wrapping_shl(self, other: u32) -> Self {
146            <Self>::wrapping_shl(self, other)
147        }
148
149        fn wrapping_shr(self, other: u32) -> Self {
150            <Self>::wrapping_shr(self, other)
151        }
152
153        fn rotate_left(self, other: u32) -> Self {
154            <Self>::rotate_left(self, other)
155        }
156
157        fn overflowing_add(self, other: Self) -> (Self, bool) {
158            <Self>::overflowing_add(self, other)
159        }
160
161        fn overflowing_sub(self, other: Self) -> (Self, bool) {
162            <Self>::overflowing_sub(self, other)
163        }
164
165        fn leading_zeros(self) -> u32 {
166            <Self>::leading_zeros(self)
167        }
168
169        fn ilog2(self) -> u32 {
170            #[allow(clippy::incompatible_msrv)]
173            <Self>::ilog2(self)
174        }
175    };
176}
177
178macro_rules! int_impl {
179    ($ity:ty, $uty:ty) => {
180        impl MinInt for $uty {
181            type OtherSign = $ity;
182            type Unsigned = $uty;
183
184            const BITS: u32 = <Self as MinInt>::ZERO.count_zeros();
185            const SIGNED: bool = Self::MIN != Self::ZERO;
186
187            const ZERO: Self = 0;
188            const ONE: Self = 1;
189            const MIN: Self = <Self>::MIN;
190            const MAX: Self = <Self>::MAX;
191        }
192
193        impl Int for $uty {
194            fn signed(self) -> $ity {
195                self as $ity
196            }
197
198            fn unsigned(self) -> Self {
199                self
200            }
201
202            fn abs(self) -> Self {
203                unimplemented!()
204            }
205
206            #[allow(clippy::wrong_self_convention)]
208            fn from_unsigned(me: $uty) -> Self {
209                me
210            }
211
212            fn abs_diff(self, other: Self) -> Self {
213                self.abs_diff(other)
214            }
215
216            int_impl_common!($uty);
217        }
218
219        impl MinInt for $ity {
220            type OtherSign = $uty;
221            type Unsigned = $uty;
222
223            const BITS: u32 = <Self as MinInt>::ZERO.count_zeros();
224            const SIGNED: bool = Self::MIN != Self::ZERO;
225
226            const ZERO: Self = 0;
227            const ONE: Self = 1;
228            const MIN: Self = <Self>::MIN;
229            const MAX: Self = <Self>::MAX;
230        }
231
232        impl Int for $ity {
233            fn signed(self) -> Self {
234                self
235            }
236
237            fn unsigned(self) -> $uty {
238                self as $uty
239            }
240
241            fn abs(self) -> Self {
242                self.abs()
243            }
244
245            fn from_unsigned(me: $uty) -> Self {
246                me as $ity
247            }
248
249            fn abs_diff(self, other: Self) -> $uty {
250                self.abs_diff(other)
251            }
252
253            int_impl_common!($ity);
254        }
255    };
256}
257
258int_impl!(isize, usize);
259int_impl!(i8, u8);
260int_impl!(i16, u16);
261int_impl!(i32, u32);
262int_impl!(i64, u64);
263int_impl!(i128, u128);
264
265pub trait DInt: MinInt {
268    type H: HInt<D = Self>;
270
271    fn lo(self) -> Self::H;
273    fn hi(self) -> Self::H;
275    fn lo_hi(self) -> (Self::H, Self::H) {
277        (self.lo(), self.hi())
278    }
279    #[allow(unused)]
281    fn from_lo_hi(lo: Self::H, hi: Self::H) -> Self {
282        lo.zero_widen() | hi.widen_hi()
283    }
284}
285
286pub trait HInt: Int {
289    type D: DInt<H = Self> + MinInt;
291
292    fn widen(self) -> Self::D;
298    fn zero_widen(self) -> Self::D;
301    #[allow(unused)]
303    fn widen_hi(self) -> Self::D;
304    fn zero_widen_mul(self, rhs: Self) -> Self::D;
306    fn widen_mul(self, rhs: Self) -> Self::D;
308}
309
310macro_rules! impl_d_int {
311    ($($X:ident $D:ident),*) => {
312        $(
313            impl DInt for $D {
314                type H = $X;
315
316                fn lo(self) -> Self::H {
317                    self as $X
318                }
319                fn hi(self) -> Self::H {
320                    (self >> <$X as MinInt>::BITS) as $X
321                }
322            }
323        )*
324    };
325}
326
327macro_rules! impl_h_int {
328    ($($H:ident $uH:ident $X:ident),*) => {
329        $(
330            impl HInt for $H {
331                type D = $X;
332
333                fn widen(self) -> Self::D {
334                    self as $X
335                }
336                fn zero_widen(self) -> Self::D {
337                    (self as $uH) as $X
338                }
339                fn zero_widen_mul(self, rhs: Self) -> Self::D {
340                    self.zero_widen().wrapping_mul(rhs.zero_widen())
341                }
342                fn widen_mul(self, rhs: Self) -> Self::D {
343                    self.widen().wrapping_mul(rhs.widen())
344                }
345                fn widen_hi(self) -> Self::D {
346                    (self as $X) << <Self as MinInt>::BITS
347                }
348            }
349        )*
350    };
351}
352
353impl_d_int!(u8 u16, u16 u32, u32 u64, u64 u128, i8 i16, i16 i32, i32 i64, i64 i128);
354impl_h_int!(
355    u8 u8 u16,
356    u16 u16 u32,
357    u32 u32 u64,
358    u64 u64 u128,
359    i8 u8 i16,
360    i16 u16 i32,
361    i32 u32 i64,
362    i64 u64 i128
363);
364
365pub trait CastInto<T: Copy>: Copy {
367    fn cast(self) -> T;
369
370    fn cast_lossy(self) -> T;
372}
373
374pub trait CastFrom<T: Copy>: Copy {
375    fn cast_from(value: T) -> Self;
377
378    fn cast_from_lossy(value: T) -> Self;
380}
381
382impl<T: Copy, U: CastInto<T> + Copy> CastFrom<U> for T {
383    fn cast_from(value: U) -> Self {
384        value.cast()
385    }
386
387    fn cast_from_lossy(value: U) -> Self {
388        value.cast_lossy()
389    }
390}
391
392macro_rules! cast_into {
393    ($ty:ty) => {
394        cast_into!($ty; usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128);
395    };
396    ($ty:ty; $($into:ty),*) => {$(
397        impl CastInto<$into> for $ty {
398            fn cast(self) -> $into {
399                #[cfg(not(feature = "compiler-builtins"))]
402                debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}");
403                self as $into
404            }
405
406            fn cast_lossy(self) -> $into {
407                self as $into
408            }
409        }
410    )*};
411}
412
413macro_rules! cast_into_float {
414    ($ty:ty) => {
415        #[cfg(f16_enabled)]
416        cast_into_float!($ty; f16);
417
418        cast_into_float!($ty; f32, f64);
419
420        #[cfg(f128_enabled)]
421        cast_into_float!($ty; f128);
422    };
423    ($ty:ty; $($into:ty),*) => {$(
424        impl CastInto<$into> for $ty {
425            fn cast(self) -> $into {
426                #[cfg(not(feature = "compiler-builtins"))]
427                debug_assert_eq!(self as $into as $ty, self, "inexact float cast");
428                self as $into
429            }
430
431            fn cast_lossy(self) -> $into {
432                self as $into
433            }
434        }
435    )*};
436}
437
438cast_into!(usize);
439cast_into!(isize);
440cast_into!(u8);
441cast_into!(i8);
442cast_into!(u16);
443cast_into!(i16);
444cast_into!(u32);
445cast_into!(i32);
446cast_into!(u64);
447cast_into!(i64);
448cast_into!(u128);
449cast_into!(i128);
450
451cast_into_float!(i8);
452cast_into_float!(i16);
453cast_into_float!(i32);
454cast_into_float!(i64);
455cast_into_float!(i128);