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 #[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 #[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) { Some(uint) => Some(Self::from_bits(uint)),
31 None => None,
32 }
33 }
34
35 #[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) { Some(uint) => Some(Self::from_bits(uint)),
43 None => None,
44 }
45 }
46
47 #[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 #[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 #[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 #[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#[cfg(test)]
169crate::test::all_digit_tests! {
170 use crate::test::{quickcheck_from_to_radix, test_bignum, self};
171 use crate::test::types::itest;
172 use crate::BInt;
173
174 test_bignum! {
175 function: <itest>::from_str_radix,
176 cases: [
177 ("-14359abcasdhfkdgdfgsde", 34u32),
178 ("+23797984569ahgkhhjdskjdfiu", 32u32),
179 ("-253613132341435345", 7u32),
180 ("+23467abcad47790809ef37", 16u32),
181 ("-712930769245766867875986646", 10u32),
182 ("-😱234292", 36u32),
183 ("-+345934758", 13u32),
184 ("12💯12", 15u32),
185 ("gap gap", 36u32),
186 ("-9223372036854775809", 10u32),
187 ("-1000000000000000000001", 8u32),
188 ("+1000000000000000000001", 8u32),
189 ("-8000000000000001", 16u32),
190 ("+-23459374", 15u32),
191 ("8000000000000000", 16u32),
192 ("", 10u32)
193 ]
194 }
195
196 quickcheck_from_to_radix!(itest, radix_be, 256);
197 quickcheck_from_to_radix!(itest, radix_le, 256);
198 quickcheck_from_to_radix!(itest, str_radix, 36);
199
200 test::quickcheck_from_str_radix!(itest, "+" | "-");
201 test::quickcheck_from_str!(itest);
202
203 #[test]
204 fn from_to_radix_le() {
205 let buf = &[
206 61, 45, 48, 20, 37, 59, 53, 28, 28, 52, 54, 13, 44, 3, 46, 42, 20, 46, 37, 32,
207 13, 27, 47, 30, 33, 25, 3, 32, 4, 54, 53, 6, 44, 25, 10, 22, 33, 48, 7, 17,
208 ];
209 let u = BInt::<100>::from_radix_le(buf, 64).unwrap();
210 let v = u.to_radix_le(64);
211 assert_eq!(v, buf);
212
213 let buf = &[
214 33, 34, 61, 53, 74, 67, 54, 62, 22, 29, 4, 2, 43, 73, 74, 24, 8, 74, 65, 3, 78,
215 ];
216 let option = BInt::<100>::from_radix_le(buf, 78);
217 assert!(option.is_none());
218
219 let buf = &[
220 1, 3, 3, 0, 2, 1, 2, 3, 0, 4, 1, 2, 0, 0, 0, 0, 3, 2, 0, 1, 0, 4, 1, 3, 1, 4,
221 3, 3, 3, 4, 1, 2, 2, 1, 3, 0, 2, 1, 2, 3, 1, 1, 0, 2, 2, 1, 1, 2, 1, 0, 0, 0,
222 3, 3, 3, 0, 0, 4, 4, 2,
223 ];
224 let u = BInt::<100>::from_radix_le(buf, 5).unwrap();
225 let v = u.to_radix_le(5);
226 assert_eq!(v, buf);
227 }
228 #[test]
229 fn from_to_radix_be() {
230 let buf = &[
231 29, 89, 92, 118, 69, 140, 141, 70, 71, 76, 66, 13, 30, 28, 38, 145, 40, 7, 57,
232 18, 25, 65, 150, 119, 155, 18, 64, 76, 106, 87,
233 ];
234 let u = BInt::<100>::from_radix_be(buf, 157).unwrap();
235 let v = u.to_radix_be(157);
236 assert_eq!(v, buf);
237
238 let buf = &[
239 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1,
240 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0,
241 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0,
242 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1,
243 ];
244 let u = BInt::<100>::from_radix_be(buf, 2).unwrap();
245 let v = u.to_radix_be(2);
246 assert_eq!(v, buf);
247
248 let buf = &[
249 91, 167, 5, 99, 61, 38, 158, 149, 115, 79, 13, 118, 53, 16, 144, 123, 70, 81,
250 78, 61, 39, 6, 34, 95, 98, 23, 175, 182,
251 ];
252 let option = BInt::<100>::from_radix_le(buf, 180);
253 assert!(option.is_none());
254
255 let buf = &[
256 39, 90, 119, 93, 95, 7, 70, 81, 3, 100, 39, 107, 98, 31, 61, 5, 36, 19, 18,
257 124, 4, 77, 119, 17, 121, 116, 24, 35,
258 ];
259 let u = BInt::<100>::from_radix_be(buf, 128).unwrap();
260 let v = u.to_radix_be(128);
261 assert_eq!(v, buf);
262 }
263 #[test]
264 fn from_to_str_radix() {
265 let src = "-293487598aashkhkhakb8345cbvjkus";
266 let u = BInt::<100>::from_str_radix(src, 35).unwrap();
267 let v = u.to_str_radix(35);
268 assert_eq!(v, src);
269
270 let src = "zzzzzzzzzzzzzzzzzzzzzzzzz";
271 let result = BInt::<1>::from_str_radix(src, 36);
272 assert!(result.is_err());
273
274 let invalid = "inval_id string";
275 let result = BInt::<1>::from_str_radix(invalid, 36);
276 assert!(result.is_err());
277
278 let src = "72954hslfhbui79845y6audfgiu984h5ihhhdfg";
279 let u = BInt::<100>::from_str_radix(src, 36).unwrap();
280 assert_eq!(u.to_str_radix(36), src);
281 }
282 #[test]
283 fn parse_bytes() {
284 let src = "1797972456987acbdead7889";
285 let u = BInt::<100>::parse_bytes(src.as_bytes(), 16).unwrap();
286 let v = BInt::<100>::from_str_radix(src, 16).unwrap();
287 assert_eq!(u, v);
288 assert_eq!(v.to_str_radix(16), src);
289
290 let bytes = b"279874657dgfhjh";
291 let option = BInt::<100>::parse_bytes(bytes, 11);
292 assert!(option.is_none());
293 }
294}
295
296crate::macro_impl!(radix);