Skip to main content

bnum/bint/
cast.rs

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