Skip to main content

bnum/bint/
convert.rs

1macro_rules! from_int {
2    ($BInt: ident, $Digit: ident; $($int: tt),*) => {
3        $(
4            impl<const N: usize> From<$int> for $BInt<N> {
5                #[inline]
6                fn from(int: $int) -> Self {
7                    let mut out = if int.is_negative() {
8                        !Self::ZERO
9                    } else {
10                        Self::ZERO
11                    };
12                    let mut i = 0;
13                    while i << crate::digit::$Digit::BIT_SHIFT < $int::BITS as usize {
14                        let d = (int >> (i << crate::digit::$Digit::BIT_SHIFT)) as $Digit;
15                        out.bits.digits[i] = d;
16                        i += 1;
17                    }
18                    out
19                }
20            }
21        )*
22    }
23}
24
25macro_rules! from_uint {
26    ($BInt: ident, $BUint: ident; $($from: tt), *) => {
27        $(
28            impl<const N: usize> From<$from> for $BInt<N> {
29                #[inline]
30                fn from(int: $from) -> Self {
31                    let out = Self::from_bits($BUint::from(int));
32                    out
33                }
34            }
35        )*
36    }
37}
38
39macro_rules! int_try_from_bint {
40    { $BInt: ident, $Digit: ident; $($int: ty), * }  => {
41        $(
42            impl<const N: usize> TryFrom<$BInt<N>> for $int {
43                type Error = TryFromIntError;
44
45                fn try_from(int: $BInt<N>) -> Result<$int, Self::Error> {
46                    let neg = int.is_negative();
47                    let (mut out, padding) = if neg {
48                        (-1, $Digit::MAX)
49                    } else {
50                        (0, $Digit::MIN)
51                    };
52                    let mut i = 0;
53                    if $Digit::BITS > <$int>::BITS {
54                        let small = int.bits.digits[i] as $int;
55                        let trunc = small as $Digit;
56                        if int.bits.digits[i] != trunc {
57                            return Err(TryFromIntError(()));
58                        }
59                        out = small;
60                        i = 1;
61                    } else {
62                        if neg {
63                            loop {
64                                let shift = i << digit::$Digit::BIT_SHIFT;
65                                if i >= N || shift >= <$int>::BITS as usize {
66                                    break;
67                                }
68                                out &= !((!int.bits.digits[i]) as $int << shift);
69                                i += 1;
70                            }
71                        } else {
72                            loop {
73                                let shift = i << digit::$Digit::BIT_SHIFT;
74                                if i >= N || shift >= <$int>::BITS as usize {
75                                    break;
76                                }
77                                out |= int.bits.digits[i] as $int << shift;
78                                i += 1;
79                            }
80                        }
81                    }
82
83                    while i < N {
84                        if int.bits.digits[i] != padding {
85                            return Err(TryFromIntError(()));
86                        }
87                        i += 1;
88                    }
89
90                    if out.is_negative() != neg {
91                        return Err(TryFromIntError(()));
92                    }
93
94                    Ok(out)
95                }
96            }
97        )*
98    };
99}
100
101macro_rules! uint_try_from_bint {
102    ($BInt: ident; $($uint: ty), *) => {
103        $(
104            impl<const N: usize> TryFrom<$BInt<N>> for $uint {
105                type Error = TryFromIntError;
106
107                #[inline]
108                fn try_from(int: $BInt<N>) -> Result<$uint, Self::Error> {
109                    if int.is_negative() {
110                        Err(TryFromIntError(()))
111                    } else {
112                        <$uint>::try_from(int.bits)
113                    }
114                }
115            }
116        )*
117    };
118}
119
120use crate::cast::CastFrom;
121use crate::digit;
122use crate::errors::{ParseIntError, TryFromIntError};
123use core::str::FromStr;
124
125macro_rules! convert {
126    ($BUint: ident, $BInt: ident, $Digit: ident) => {
127        impl<const N: usize> FromStr for $BInt<N> {
128            type Err = ParseIntError;
129
130            #[inline]
131            fn from_str(src: &str) -> Result<Self, Self::Err> {
132                Self::from_str_radix(src, 10)
133            }
134        }
135
136        from_int!($BInt, $Digit; i8, i16, i32, i64, i128, isize);
137
138        from_uint!($BInt, $BUint; u8, u16, u32, u64, u128, usize);
139
140        impl<const N: usize> From<bool> for $BInt<N> {
141            #[inline]
142            fn from(small: bool) -> Self {
143                Self::cast_from(small)
144            }
145        }
146
147        int_try_from_bint!($BInt, $Digit; i8, i16, i32, i64, i128, isize);
148        uint_try_from_bint!($BInt; u8, u16, u32, u64, u128, usize);
149
150        // impl_const! {
151        //     impl<const N: usize> const TryFrom<$BUint<N>> for $BInt<N> {
152        //         type Error = TryFromIntError;
153
154        //         #[inline]
155        //         fn try_from(u: $BUint<N>) -> Result<Self, Self::Error> {
156        //             if u.leading_ones() != 0 {
157        //                 Err(TryFromIntError(()))
158        //             } else {
159        //                 Ok(Self::from_bits(u))
160        //             }
161        //         }
162        //     }
163        // }
164    };
165}
166
167#[cfg(test)]
168crate::test::all_digit_tests! {
169    use crate::test;
170    use crate::test::types::itest;
171    use crate::test::cast_types::*;
172    use crate::BTryFrom;
173    
174    test::test_btryfrom!(itest; TestUint1, TestUint2, TestUint3, TestUint4, TestUint5, TestUint6, TestUint7, TestUint8, TestUint9, TestUint10, TestInt1, TestInt2, TestInt3, TestInt4, TestInt5, TestInt6, TestInt7, TestInt8, TestInt9, TestInt10);
175
176    #[cfg(test_int_bits = "128")]
177    test::test_from! {
178        function: <itest as TryFrom>::try_from,
179        from_types: (i8, i16, i32, i64, i128, u8, u16, u32, u64, bool, usize, isize)
180    }
181
182    #[cfg(test_int_bits = "64")]
183    test::test_from! {
184        function: <itest as TryFrom>::try_from,
185        from_types: (i8, i16, i32, i64, u8, u16, u32, bool, isize)
186    }
187
188    test::test_into! {
189        function: <itest as TryInto>::try_into,
190        into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize)
191    }
192}
193
194crate::macro_impl!(convert);