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);