reweb3_num/buint/
cast.rs

1macro_rules! decode_float {
2    ($name: ident, $f: ty, $u: ty) => {
3        pub fn $name(f: $f) -> ($u, i16) {
4            const BITS: u32 = core::mem::size_of::<$f>() as u32 * 8;
5            const MANT_MASK: $u = <$u>::MAX >> (BITS - (<$f>::MANTISSA_DIGITS - 1));
6            const EXP_MASK: $u = <$u>::MAX >> 1;
7            const BIAS: i16 = <$f>::MAX_EXP as i16 - 1;
8
9            let bits = f.to_bits();
10            let exp = ((bits & EXP_MASK) >> (<$f>::MANTISSA_DIGITS - 1)) as i16;
11            let mut mant = bits & MANT_MASK;
12            if exp != 0 {
13                mant |= (1 << (<$f>::MANTISSA_DIGITS - 1));
14            }
15            (mant, exp - (BIAS + <$f>::MANTISSA_DIGITS as i16 - 1))
16        }
17    };
18}
19
20decode_float!(decode_f32, f32, u32);
21decode_float!(decode_f64, f64, u64);
22
23macro_rules! buint_as_int {
24    ($BUint: ident, $Digit: ident; $($int: ty), *) => {
25        $(impl_const! {
26            impl<const N: usize> const CastFrom<$BUint<N>> for $int {
27                #[must_use = doc::must_use_op!()]
28                #[inline]
29                fn cast_from(from: $BUint<N>) -> Self {
30                    let mut out = 0;
31                    let mut i = 0;
32                    while i << crate::digit::$Digit::BIT_SHIFT < <$int>::BITS as usize && i < N {
33                        out |= from.digits[i] as $int << (i << crate::digit::$Digit::BIT_SHIFT);
34                        i += 1;
35                    }
36                    out
37                }
38            }
39        })*
40    };
41}
42
43macro_rules! buint_as_float {
44    ($BUint: ident, $f: ty) => {
45        impl<const N: usize> CastFrom<$BUint<N>> for $f {
46            #[must_use = doc::must_use_op!()]
47            #[inline]
48            fn cast_from(from: $BUint<N>) -> Self {
49                crate::buint::as_float::cast_float_from_uint(from)
50                /*if from.is_zero() {
51                    return 0.0;
52                }
53                let bits = from.bits();
54                let mut mant = if $BUint::<N>::BITS > <$u>::BITS {
55                    if bits < <$f>::MANTISSA_DIGITS {
56                        <$u>::cast_from(from) << (<$f>::MANTISSA_DIGITS - bits)
57                    } else {
58                        <$u>::cast_from(from >> (bits - <$f>::MANTISSA_DIGITS))
59                    }
60                } else if bits < <$f>::MANTISSA_DIGITS {
61                    <$u>::cast_from(from) << (<$f>::MANTISSA_DIGITS - bits)
62                } else {
63                    <$u>::cast_from(from) >> (bits - <$f>::MANTISSA_DIGITS)
64                };
65                let mut round_up = true;
66                if bits <= <$f>::MANTISSA_DIGITS
67                    || !from.bit(bits - (<$f>::MANTISSA_DIGITS + 1))
68                    || (mant & 1 == 0
69                        && from.trailing_zeros() == bits - (<$f>::MANTISSA_DIGITS + 1))
70                {
71                    round_up = false;
72                }
73                let mut exp = bits as $u + (<$f>::MAX_EXP - 1) as $u - 1;
74                if round_up {
75                    mant += 1;
76                    if mant.leading_zeros() == <$u>::BITS - (<$f>::MANTISSA_DIGITS + 1) {
77                        exp += 1;
78                    }
79                }
80                if exp > 2 * (<$f>::MAX_EXP as $u) - 1 {
81                    return <$f>::INFINITY;
82                }
83                let mant = <$u>::cast_from(mant);
84                <$f>::from_bits(
85                    (exp << (<$f>::MANTISSA_DIGITS - 1))
86                        | (mant & (<$u>::MAX >> (<$u>::BITS - (<$f>::MANTISSA_DIGITS as u32 - 1)))),
87                )*/
88            }
89        }
90    };
91}
92
93macro_rules! as_buint {
94    ($BUint: ident, $Digit: ident; $($ty: ty), *) => {
95        $(crate::nightly::const_impl! {
96            impl<const N: usize> const CastFrom<$ty> for $BUint<N> {
97                #[must_use = doc::must_use_op!()]
98                #[inline]
99                fn cast_from(mut from: $ty) -> Self {
100                    #[allow(unused_comparisons)]
101                    let mut out = if from < 0 {
102                        Self::MAX
103                    } else {
104                        Self::MIN
105                    };
106                    let mut i = 0;
107                    while from != 0 && i < N {
108                        let masked = from as $Digit & $Digit::MAX;
109                        out.digits[i] = masked;
110                        if <$ty>::BITS <= $Digit::BITS {
111                            from = 0;
112                        } else {
113                            from = from.wrapping_shr($Digit::BITS);
114                        }
115                        i += 1;
116                    }
117                    out
118                }
119            }
120        })*
121    };
122}
123
124use crate::cast::CastFrom;
125use crate::doc;
126use crate::nightly::impl_const;
127// use core::mem::MaybeUninit;
128
129macro_rules! cast {
130    ($BUint: ident, $BInt: ident, $Digit: ident) => {
131        impl<const N: usize> $BUint<N> {
132            crate::nightly::const_fn! {
133                #[inline]
134                const fn cast_up<const M: usize>(self, digit: $Digit) -> $BUint<M> {
135                    let mut digits = [digit; M];
136                    let mut i = M - N;
137                    while i < M {
138                        let index = i - (M - N);
139                        digits[index] = self.digits[index];
140                        i += 1;
141                    }
142                    $BUint::from_digits(digits)
143                }
144            }
145            crate::nightly::const_fn! {
146                #[inline]
147                const fn cast_down<const M: usize>(self) -> $BUint<M> {
148                    let mut out = $BUint::ZERO;
149                    let mut i = 0;
150                    while i < M {
151                        out.digits[i] = self.digits[i];
152                        i += 1;
153                    }
154                    out
155                }
156            }
157        }
158
159        buint_as_int!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
160
161        buint_as_float!($BUint, f32);
162        buint_as_float!($BUint, f64);
163
164        as_buint!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
165
166        impl_const! {
167            impl<const N: usize> const CastFrom<bool> for $BUint<N> {
168                #[must_use = doc::must_use_op!()]
169                #[inline]
170                fn cast_from(from: bool) -> Self {
171                    if from {
172                        Self::ONE
173                    } else {
174                        Self::ZERO
175                    }
176                }
177            }
178        }
179
180        impl_const! {
181            impl<const N: usize> const CastFrom<char> for $BUint<N> {
182                #[must_use = doc::must_use_op!()]
183                #[inline]
184                fn cast_from(from: char) -> Self {
185                    Self::cast_from(from as u32)
186                }
187            }
188        }
189
190        impl_const! {
191            impl<const N: usize, const M: usize> const CastFrom<$BUint<M>> for $BUint<N> {
192                #[must_use = doc::must_use_op!()]
193                #[inline]
194                fn cast_from(from: $BUint<M>) -> Self {
195                    if M < N {
196                        from.cast_up(0)
197                    } else {
198                        from.cast_down()
199                    }
200                }
201            }
202        }
203
204        impl_const! {
205            impl<const N: usize, const M: usize> const CastFrom<$BInt<M>> for $BUint<N> {
206                #[must_use = doc::must_use_op!()]
207                #[inline]
208                fn cast_from(from: $BInt<M>) -> Self {
209                    if M < N {
210                        let padding_digit = if from.is_negative() {
211                            $Digit::MAX
212                        } else {
213                            0
214                        };
215                        from.to_bits().cast_up(padding_digit)
216                    } else {
217                        from.to_bits().cast_down()
218                    }
219                }
220            }
221        }
222
223        impl<const N: usize> CastFrom<f32> for $BUint<N> {
224            #[must_use = doc::must_use_op!()]
225            #[inline]
226            fn cast_from(from: f32) -> Self {
227                crate::buint::float_as::uint_cast_from_float(from)
228            }
229        }
230
231        impl<const N: usize> CastFrom<f64> for $BUint<N> {
232            #[must_use = doc::must_use_op!()]
233            #[inline]
234            fn cast_from(from: f64) -> Self {
235                crate::buint::float_as::uint_cast_from_float(from)
236            }
237        }
238
239    };
240}
241
242crate::macro_impl!(cast);
243
244macro_rules! buint_as_different_digit_bigint {
245    ($BUint: ident, $BInt: ident, $Digit: ident; $(($OtherBUint: ident, $OtherDigit: ident)), *) => {
246        $(
247            crate::nightly::const_impl! {
248                impl<const N: usize, const M: usize> const crate::cast::CastFrom<$OtherBUint<M>> for $BUint<N> {
249                    #[must_use = doc::must_use_op!()]
250                    #[inline]
251                    fn cast_from(from: $OtherBUint<M>) -> Self {
252                        let mut out = Self::ZERO;
253                        if $Digit::BITS < $OtherDigit::BITS {
254                            const DIVIDE_COUNT: usize = ($OtherDigit::BITS / $Digit::BITS) as usize;
255                            let stop_index: usize = if <$OtherBUint<M>>::BITS > <$BUint<N>>::BITS {
256                                N
257                            } else {
258                                M * DIVIDE_COUNT
259                            };
260                            let mut i = 0;
261                            while i < stop_index {
262                                let wider_digit = from.digits[i / DIVIDE_COUNT];
263                                let mini_shift = i % DIVIDE_COUNT;
264                                let digit = (wider_digit >> (mini_shift << digit::$Digit::BIT_SHIFT)) as $Digit;
265                                out.digits[i] = digit;
266                                i += 1;
267                            }
268                        } else {
269                            const DIVIDE_COUNT: usize = ($Digit::BITS / $OtherDigit::BITS) as usize;
270                            let stop_index: usize = if <$OtherBUint<M>>::BITS > <$BUint<N>>::BITS {
271                                N * DIVIDE_COUNT
272                            } else {
273                                M
274                            };
275                            let mut current_digit: $Digit = 0;
276                            let mut i = 0;
277                            while i < stop_index {
278                                let mini_shift = i % DIVIDE_COUNT;
279                                current_digit |= (from.digits[i] as $Digit) << (mini_shift << digit::$OtherDigit::BIT_SHIFT);
280                                if mini_shift == DIVIDE_COUNT - 1 || i == stop_index - 1 {
281                                    out.digits[i / DIVIDE_COUNT] = current_digit;
282                                    current_digit = 0;
283                                }
284                                i += 1;
285                            }
286                        }
287                        out
288                    }
289                }
290            }
291
292            crate::nightly::const_impl! {
293                impl<const N: usize, const M: usize> const crate::cast::CastFrom<$OtherBUint<M>> for $BInt<N> {
294                    #[must_use = doc::must_use_op!()]
295                    #[inline]
296                    fn cast_from(from: $OtherBUint<M>) -> Self {
297                        Self::from_bits($BUint::cast_from(from))
298                    }
299                }
300            }
301        )*
302    }
303}
304
305pub(crate) use buint_as_different_digit_bigint;