reweb3_num/bint/
radix.rs

1use crate::doc;
2use crate::errors::ParseIntError;
3use crate::int::radix::assert_range;
4use alloc::string::String;
5use alloc::vec::Vec;
6use core::num::IntErrorKind;
7
8macro_rules! radix {
9    ($BUint: ident, $BInt: ident, $Digit: ident) => {
10        #[doc = doc::radix::impl_desc!($BInt)]
11        impl<const N: usize> $BInt<N> {
12            /// Converts a byte slice in a given base to an integer. The input slice must contain ascii/utf8 characters in [0-9a-zA-Z].
13            ///
14            /// This function is equivalent to the [`from_str_radix`](#method.from_str_radix) function for a string slice equivalent to the byte slice and the same radix.
15            ///
16            /// Returns `None` if the conversion of the byte slice to string slice fails or if a digit is larger than or equal to the given radix, otherwise the integer is wrapped in `Some`.
17            #[inline]
18            pub const fn parse_bytes(buf: &[u8], radix: u32) -> Option<Self> {
19                let s = crate::nightly::option_try!(crate::nightly::ok!(core::str::from_utf8(buf)));
20                crate::nightly::ok!(Self::from_str_radix(s, radix))
21            }
22
23            /// Converts a slice of big-endian digits in the given radix to an integer. The digits are first converted to an unsigned integer, then this is transmuted to a signed integer. Each `u8` of the slice is interpreted as one digit of base `radix` of the number, so this function will return `None` if any digit is greater than or equal to `radix`, otherwise the integer is wrapped in `Some`.
24            ///
25            /// For examples, see the
26            #[doc = concat!("[`from_radix_be`](crate::", stringify!($BUint), "::from_radix_be) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")]
27            #[inline]
28            pub const fn from_radix_be(buf: &[u8], radix: u32) -> Option<Self> {
29                match $BUint::from_radix_be(buf, radix) { // TODO: use Option::map when stable
30                    Some(uint) => Some(Self::from_bits(uint)),
31                    None => None,
32                }
33            }
34
35            /// Converts a slice of big-endian digits in the given radix to an integer. The digits are first converted to an unsigned integer, then this is transmuted to a signed integer. Each `u8` of the slice is interpreted as one digit of base `radix` of the number, so this function will return `None` if any digit is greater than or equal to `radix`, otherwise the integer is wrapped in `Some`.
36            ///
37            /// For examples, see the
38            #[doc = concat!("[`from_radix_le`](crate::", stringify!($BUint), "::from_radix_le) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")]
39            #[inline]
40            pub const fn from_radix_le(buf: &[u8], radix: u32) -> Option<Self> {
41                match $BUint::from_radix_le(buf, radix) { // TODO: use Option::map when stable
42                    Some(uint) => Some(Self::from_bits(uint)),
43                    None => None,
44                }
45            }
46
47            /// Converts a string slice in a given base to an integer.
48            ///
49            /// The string is expected to be an optional `+` or `-` sign followed by digits. Leading and trailing whitespace represent an error. Digits are a subset of these characters, depending on `radix`:
50            ///
51            /// - `0-9`
52            /// - `a-z`
53            /// - `A-Z`
54            ///
55            /// # Panics
56            ///
57            /// This function panics if `radix` is not in the range from 2 to 36 inclusive.
58            ///
59            /// For examples, see the
60            #[doc = concat!("[`from_str_radix`](crate::", stringify!($BUint), "::from_str_radix) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")]
61            #[inline]
62            pub const fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
63                assert_range!(radix, 36);
64                if src.is_empty() {
65                    return Err(ParseIntError {
66                        kind: IntErrorKind::Empty,
67                    });
68                }
69                let mut negative = false;
70                let mut leading_sign = false;
71                let buf = src.as_bytes();
72                if buf[0] == b'-' {
73                    negative = true;
74                    leading_sign = true;
75                } else if buf[0] == b'+' {
76                    leading_sign = true;
77                }
78
79                match $BUint::from_buf_radix_internal::<true, true>(buf, radix, leading_sign) {
80                    Ok(uint) => {
81                        if negative {
82                            if uint.bit(Self::BITS - 1) && uint.trailing_zeros() != Self::BITS - 1 {
83                                Err(ParseIntError {
84                                    kind: IntErrorKind::NegOverflow,
85                                })
86                            } else {
87                                Ok(Self::from_bits(uint).wrapping_neg())
88                            }
89                        } else {
90                            let out = Self::from_bits(uint);
91                            if out.is_negative() {
92                                Err(ParseIntError {
93                                    kind: IntErrorKind::PosOverflow,
94                                })
95                            } else {
96                                Ok(out)
97                            }
98                        }
99                    }
100                    Err(err) => {
101                        if let IntErrorKind::PosOverflow = err.kind() {
102                            if negative {
103                                return Err(ParseIntError {
104                                    kind: IntErrorKind::NegOverflow,
105                                });
106                            }
107                        }
108                        return Err(err)
109                    }
110                }
111            }
112
113            #[doc = doc::radix::parse_str_radix!($BUint)]
114            #[inline]
115            pub const fn parse_str_radix(src: &str, radix: u32) -> Self {
116                match Self::from_str_radix(src, radix) {
117                    Ok(n) => n,
118                    Err(e) => panic!("{}", e.description()),
119                }
120            }
121
122            /// Returns the integer as a string in the given radix.
123            ///
124            /// # Panics
125            ///
126            /// This function panics if `radix` is not in the range from 2 to 36 inclusive.
127            ///
128            /// For examples, see the
129            #[doc = concat!("[`to_str_radix`](crate::", stringify!($BUint), "::to_str_radix) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")]
130            #[inline]
131            pub fn to_str_radix(&self, radix: u32) -> String {
132                if self.is_negative() {
133                    format!("-{}", self.unsigned_abs().to_str_radix(radix))
134                } else {
135                    self.bits.to_str_radix(radix)
136                }
137            }
138
139            /// Returns the integer's underlying representation as an unsigned integer in the given base in big-endian digit order.
140            ///
141            /// # Panics
142            ///
143            /// This function panics if `radix` is not in the range from 2 to 256 inclusive.
144            ///
145            /// For examples, see the
146            #[doc = concat!("[`to_radix_be`](crate::", stringify!($BUint), "::to_radix_be) method documentation for [`", stringify!($BUint), "`]")]
147            #[inline]
148            pub fn to_radix_be(&self, radix: u32) -> Vec<u8> {
149                self.bits.to_radix_be(radix)
150            }
151
152            /// Returns the integer's underlying representation as an unsigned integer in the given base in little-endian digit order.
153            ///
154            /// # Panics
155            ///
156            /// This function panics if `radix` is not in the range from 2 to 256 inclusive.
157            ///
158            /// For examples, see the
159            #[doc = concat!("[`to_radix_le`](crate::", stringify!($BUint), "::to_radix_le) method documentation for [`", stringify!($BUint), "`](crate::", stringify!($BUint), ").")]
160            #[inline]
161            pub fn to_radix_le(&self, radix: u32) -> Vec<u8> {
162                self.bits.to_radix_le(radix)
163            }
164        }
165
166    };
167}
168
169crate::macro_impl!(radix);