Skip to main content

bnum/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        $(
26            impl<const N: usize> 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(value: $BUint<N>) -> Self {
49                crate::cast::float::cast_float_from_uint(value)
50            }
51        }
52    };
53}
54
55macro_rules! as_buint {
56    ($BUint: ident, $Digit: ident; $($ty: ty), *) => {
57        $(
58            impl<const N: usize> CastFrom<$ty> for $BUint<N> {
59                #[must_use = doc::must_use_op!()]
60                #[inline]
61                fn cast_from(mut from: $ty) -> Self {
62                    #[allow(unused_comparisons)]
63                    let mut out = if from < 0 {
64                        Self::MAX
65                    } else {
66                        Self::MIN
67                    };
68                    let mut i = 0;
69                    while from != 0 && i < N {
70                        let masked = from as $Digit & $Digit::MAX;
71                        out.digits[i] = masked;
72                        if <$ty>::BITS <= $Digit::BITS {
73                            from = 0;
74                        } else {
75                            from = from.wrapping_shr($Digit::BITS);
76                        }
77                        i += 1;
78                    }
79                    out
80                }
81            }
82        )*
83    };
84}
85
86use crate::cast::CastFrom;
87use crate::doc;
88use crate::ExpType;
89#[allow(unused_imports)]
90use crate::cast::float::{FloatMantissa, CastUintFromFloatHelper, CastFloatFromUintHelper};
91
92macro_rules! cast {
93    ($BUint: ident, $BInt: ident, $Digit: ident) => {
94        // #[cfg(feature = "float")]
95        // impl<const N: usize> FloatMantissa for $BUint<N> {
96        //     const ZERO: Self = Self::ZERO;
97        //     const ONE: Self = Self::ONE;
98        //     const TWO: Self = Self::TWO;
99        //     const MAX: Self = Self::MAX;
100
101        //     #[inline]
102        //     fn leading_zeros(self) -> ExpType {
103        //         Self::leading_zeros(self)
104        //     }
105
106        //     #[inline]
107        //     fn checked_shr(self, n: ExpType) -> Option<Self> {
108        //         Self::checked_shr(self, n)
109        //     }
110
111        //     #[inline]
112        //     fn is_power_of_two(self) -> bool {
113        //         Self::is_power_of_two(self)
114        //     }
115        // }
116
117        impl<const N: usize> CastUintFromFloatHelper for $BUint<N> {
118            const MAX: Self = Self::MAX;
119            const MIN: Self = Self::MIN;
120        }
121
122        impl<const N: usize> CastFloatFromUintHelper for $BUint<N> {
123            fn trailing_zeros(self) -> ExpType {
124                Self::trailing_zeros(self)
125            }
126        }
127
128        impl<const N: usize> $BUint<N> {
129            #[inline]
130            const fn cast_up<const M: usize>(self, digit: $Digit) -> $BUint<M> {
131                let mut digits = [digit; M];
132                let mut i = M - N;
133                while i < M {
134                    let index = i - (M - N);
135                    digits[index] = self.digits[index];
136                    i += 1;
137                }
138                $BUint::from_digits(digits)
139            }
140
141            #[inline]
142            const fn cast_down<const M: usize>(self) -> $BUint<M> {
143                let mut out = $BUint::ZERO;
144                let mut i = 0;
145                while i < M {
146                    out.digits[i] = self.digits[i];
147                    i += 1;
148                }
149                out
150            }
151        }
152
153        buint_as_int!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
154
155        buint_as_float!($BUint, f32);
156        buint_as_float!($BUint, f64);
157
158        as_buint!($BUint, $Digit; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
159
160        impl<const N: usize> CastFrom<bool> for $BUint<N> {
161            #[must_use = doc::must_use_op!()]
162            #[inline]
163            fn cast_from(from: bool) -> Self {
164                if from {
165                    Self::ONE
166                } else {
167                    Self::ZERO
168                }
169            }
170        }
171
172        impl<const N: usize> CastFrom<char> for $BUint<N> {
173            #[must_use = doc::must_use_op!()]
174            #[inline]
175            fn cast_from(from: char) -> Self {
176                Self::cast_from(from as u32)
177            }
178        }
179
180        impl<const N: usize, const M: usize> CastFrom<$BUint<M>> for $BUint<N> {
181            #[must_use = doc::must_use_op!()]
182            #[inline]
183            fn cast_from(from: $BUint<M>) -> Self {
184                if M < N {
185                    from.cast_up(0)
186                } else {
187                    from.cast_down()
188                }
189            }
190        }
191
192        impl<const N: usize, const M: usize> CastFrom<$BInt<M>> for $BUint<N> {
193            #[must_use = doc::must_use_op!()]
194            #[inline]
195            fn cast_from(from: $BInt<M>) -> Self {
196                if M < N {
197                    let padding_digit = if from.is_negative() {
198                        $Digit::MAX
199                    } else {
200                        0
201                    };
202                    from.to_bits().cast_up(padding_digit)
203                } else {
204                    from.to_bits().cast_down()
205                }
206            }
207        }
208
209        impl<const N: usize> CastFrom<f32> for $BUint<N> {
210            #[must_use = doc::must_use_op!()]
211            #[inline]
212            fn cast_from(value: f32) -> Self {
213                crate::cast::float::cast_uint_from_float(value)
214            }
215        }
216
217        impl<const N: usize> CastFrom<f64> for $BUint<N> {
218            #[must_use = doc::must_use_op!()]
219            #[inline]
220            fn cast_from(value: f64) -> Self {
221                crate::cast::float::cast_uint_from_float(value)
222            }
223        }
224    };
225}
226
227#[cfg(test)]
228crate::test::all_digit_tests! {
229    crate::int::cast::tests!(utest);
230}
231
232crate::macro_impl!(cast);
233
234macro_rules! buint_as_different_digit_bigint {
235    ($BUint: ident, $BInt: ident, $Digit: ident; $(($OtherBUint: ident, $OtherDigit: ident)), *) => {
236        $(
237            impl<const N: usize, const M: usize> crate::cast::CastFrom<$OtherBUint<M>> for $BUint<N> {
238                #[must_use = doc::must_use_op!()]
239                #[inline]
240                fn cast_from(from: $OtherBUint<M>) -> Self {
241                    let mut out = Self::ZERO;
242                    if $Digit::BITS < $OtherDigit::BITS {
243                        const DIVIDE_COUNT: usize = ($OtherDigit::BITS / $Digit::BITS) as usize;
244                        let stop_index: usize = if <$OtherBUint<M>>::BITS > <$BUint<N>>::BITS {
245                            N
246                        } else {
247                            M * DIVIDE_COUNT
248                        };
249                        let mut i = 0;
250                        while i < stop_index {
251                            let wider_digit = from.digits[i / DIVIDE_COUNT];
252                            let mini_shift = i % DIVIDE_COUNT;
253                            let digit = (wider_digit >> (mini_shift << digit::$Digit::BIT_SHIFT)) as $Digit;
254                            out.digits[i] = digit;
255                            i += 1;
256                        }
257                    } else {
258                        const DIVIDE_COUNT: usize = ($Digit::BITS / $OtherDigit::BITS) as usize;
259                        let stop_index: usize = if <$OtherBUint<M>>::BITS > <$BUint<N>>::BITS {
260                            N * DIVIDE_COUNT
261                        } else {
262                            M
263                        };
264                        let mut current_digit: $Digit = 0;
265                        let mut i = 0;
266                        while i < stop_index {
267                            let mini_shift = i % DIVIDE_COUNT;
268                            current_digit |= (from.digits[i] as $Digit) << (mini_shift << digit::$OtherDigit::BIT_SHIFT);
269                            if mini_shift == DIVIDE_COUNT - 1 || i == stop_index - 1 {
270                                out.digits[i / DIVIDE_COUNT] = current_digit;
271                                current_digit = 0;
272                            }
273                            i += 1;
274                        }
275                    }
276                    out
277                }
278            }
279
280            impl<const N: usize, const M: usize> crate::cast::CastFrom<$OtherBUint<M>> for $BInt<N> {
281                #[must_use = doc::must_use_op!()]
282                #[inline]
283                fn cast_from(from: $OtherBUint<M>) -> Self {
284                    Self::from_bits($BUint::cast_from(from))
285                }
286            }
287        )*
288    }
289}
290
291pub(crate) use buint_as_different_digit_bigint;