reweb3_num/bint/
cast.rs

1macro_rules! bint_as {
2    ($BInt: ident, $Digit: ident; $($int: ty), *) => {
3        $(
4            impl_const! {
5                impl<const N: usize> const CastFrom<$BInt<N>> for $int {
6                    #[inline]
7                    fn cast_from(from: $BInt<N>) -> Self {
8                        if from.is_negative() {
9                            let digits = from.bits.digits;
10                            let mut out = !0;
11                            let mut i = 0;
12                            while i << digit::$Digit::BIT_SHIFT < <$int>::BITS as usize && i < N {
13                                out &= !((!digits[i]) as $int << (i << digit::$Digit::BIT_SHIFT));
14                                i += 1;
15                            }
16                            out
17                        } else {
18                            <$int>::cast_from(from.bits)
19                        }
20                    }
21                }
22            }
23        )*
24    };
25}
26
27macro_rules! as_bint {
28    ($BInt: ident, $BUint: ident; $($ty: ty), *) => {
29        $(impl_const! {
30            impl<const N: usize> const CastFrom<$ty> for $BInt<N> {
31                #[inline]
32                fn cast_from(from: $ty) -> Self {
33                    Self::from_bits($BUint::cast_from(from))
34                }
35            }
36        })*
37    }
38}
39
40macro_rules! bint_cast_from_float {
41    ($f: ty, $BUint: ident <$N: ident>) => {
42        #[inline]
43        fn cast_from(from: $f) -> Self {
44            if from.is_sign_negative() {
45                let u = $BUint::<$N>::cast_from(-from);
46                if u >= Self::MIN.to_bits() {
47                    Self::MIN
48                } else {
49                    -Self::from_bits(u)
50                }
51            } else {
52                let u = $BUint::<$N>::cast_from(from);
53                let i = Self::from_bits(u);
54                if i.is_negative() {
55                    Self::MAX
56                } else {
57                    i
58                }
59            }
60        }
61    };
62}
63
64pub(crate) use bint_cast_from_float;
65
66use crate::cast::CastFrom;
67use crate::digit;
68use crate::nightly::impl_const;
69
70macro_rules! cast {
71    ($BUint: ident, $BInt: ident, $Digit: ident) => {
72        bint_as!($BInt, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
73
74        impl<const N: usize> CastFrom<$BInt<N>> for f32 {
75            #[inline]
76            fn cast_from(from: $BInt<N>) -> Self {
77                let f = f32::cast_from(from.unsigned_abs());
78                if from.is_negative() {
79                    -f
80                } else {
81                    f
82                }
83            }
84        }
85
86        impl<const N: usize> CastFrom<$BInt<N>> for f64 {
87            #[inline]
88            fn cast_from(from: $BInt<N>) -> Self {
89                let f = f64::cast_from(from.unsigned_abs());
90                if from.is_negative() {
91                    -f
92                } else {
93                    f
94                }
95            }
96        }
97
98        as_bint!($BInt, $BUint; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, bool, char);
99
100        impl_const! {
101            impl<const N: usize, const M: usize> const CastFrom<$BUint<M>> for $BInt<N> {
102                #[inline]
103                fn cast_from(from: $BUint<M>) -> Self {
104                    Self::from_bits($BUint::cast_from(from))
105                }
106            }
107        }
108
109        impl_const! {
110            impl<const N: usize, const M: usize> const CastFrom<$BInt<M>> for $BInt<N> {
111                #[inline]
112                fn cast_from(from: $BInt<M>) -> Self {
113                    Self::from_bits($BUint::cast_from(from))
114                }
115            }
116        }
117
118        impl<const N: usize> CastFrom<f32> for $BInt<N> {
119            crate::bint::cast::bint_cast_from_float!(f32, $BUint<N>);
120        }
121
122        impl<const N: usize> CastFrom<f64> for $BInt<N> {
123            crate::bint::cast::bint_cast_from_float!(f64, $BUint<N>);
124        }
125    };
126}
127
128crate::macro_impl!(cast);
129
130macro_rules! bint_as_different_digit_bigint {
131    ($BUint: ident, $BInt: ident, $Digit: ident; $(($OtherBInt: ident, $OtherDigit: ident)), *) => {
132        $(
133            crate::nightly::const_impl! {
134                impl<const N: usize, const M: usize> const crate::cast::CastFrom<$OtherBInt<M>> for $BUint<N> {
135                    #[must_use = doc::must_use_op!()]
136                    #[inline]
137                    fn cast_from(from: $OtherBInt<M>) -> Self {
138                        if !from.is_negative() || M * $OtherDigit::BITS as usize >= N * $Digit::BITS as usize { // $OtherBInt::BITS <= $Int::BITS
139                            Self::cast_from(from.to_bits())
140                        } else {
141                            let mut out = Self::MAX;
142                            if $Digit::BITS < $OtherDigit::BITS {
143                                const DIVIDE_COUNT: usize = ($OtherDigit::BITS / $Digit::BITS) as usize;
144                                let stop_index: usize = if <$OtherBInt<M>>::BITS > <$BUint<N>>::BITS {
145                                    N
146                                } else {
147                                    M * DIVIDE_COUNT
148                                };
149                                let mut i = 0;
150                                while i < stop_index {
151                                    let wider_digit = from.bits.digits[i / DIVIDE_COUNT];
152                                    let mini_shift = i % DIVIDE_COUNT;
153                                    let digit = (wider_digit >> (mini_shift << digit::$Digit::BIT_SHIFT)) as $Digit;
154                                    out.digits[i] = digit;
155                                    i += 1;
156                                }
157                            } else {
158                                const DIVIDE_COUNT: usize = ($Digit::BITS / $OtherDigit::BITS) as usize;
159                                let stop_index: usize = if <$OtherBInt<M>>::BITS > <$BUint<N>>::BITS {
160                                    N * DIVIDE_COUNT
161                                } else {
162                                    M
163                                };
164                                let mut current_digit: $Digit = $Digit::MAX;
165                                let mut i = 0;
166                                while i < stop_index {
167                                    let mini_shift = i % DIVIDE_COUNT;
168                                    current_digit &= !((!from.bits.digits[i] as $Digit) << (mini_shift << digit::$OtherDigit::BIT_SHIFT));
169                                    if mini_shift == DIVIDE_COUNT - 1 || i == stop_index - 1 {
170                                        out.digits[i / DIVIDE_COUNT] = current_digit;
171                                        current_digit = $Digit::MAX;
172                                    }
173                                    i += 1;
174                                }
175                            }
176                            out
177                        }
178                    }
179                }
180            }
181
182            crate::nightly::const_impl! {
183                impl<const N: usize, const M: usize> const crate::cast::CastFrom<$OtherBInt<M>> for $BInt<N> {
184                    #[must_use = doc::must_use_op!()]
185                    #[inline]
186                    fn cast_from(from: $OtherBInt<M>) -> Self {
187                        Self::from_bits($BUint::<N>::cast_from(from))
188                    }
189                }
190            }
191        )*
192    };
193}
194
195pub(crate) use bint_as_different_digit_bigint;