cw_bigint/biguint/
convert.rs1use super::{biguint_from_vec, BigUint, ToBigUint};
2
3use crate::big_digit::{self, BigDigit};
4use crate::std_alloc::Vec;
5use crate::ParseBigIntError;
6#[cfg(has_try_from)]
7use crate::TryFromBigIntError;
8
9#[cfg(has_try_from)]
10use core::convert::TryFrom;
11use core::mem;
12use core::str::FromStr;
13use num_integer::Integer;
14use num_traits::{FromPrimitive, Num, PrimInt, ToPrimitive, Zero};
15
16fn fls<T: PrimInt>(v: T) -> u8 {
19 mem::size_of::<T>() as u8 * 8 - v.leading_zeros() as u8
20}
21
22fn ilog2<T: PrimInt>(v: T) -> u8 {
23 fls(v) - 1
24}
25
26impl FromStr for BigUint {
27 type Err = ParseBigIntError;
28
29 #[inline]
30 fn from_str(s: &str) -> Result<BigUint, ParseBigIntError> {
31 BigUint::from_str_radix(s, 10)
32 }
33}
34
35pub(super) fn from_bitwise_digits_le(v: &[u8], bits: u8) -> BigUint {
38 debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits == 0);
39 debug_assert!(v.iter().all(|&c| BigDigit::from(c) < (1 << bits)));
40
41 let digits_per_big_digit = big_digit::BITS / bits;
42
43 let data = v
44 .chunks(digits_per_big_digit.into())
45 .map(|chunk| {
46 chunk
47 .iter()
48 .rev()
49 .fold(0, |acc, &c| (acc << bits) | BigDigit::from(c))
50 })
51 .collect();
52
53 biguint_from_vec(data)
54}
55
56fn from_inexact_bitwise_digits_le(v: &[u8], bits: u8) -> BigUint {
59 debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits != 0);
60 debug_assert!(v.iter().all(|&c| BigDigit::from(c) < (1 << bits)));
61
62 let total_bits = (v.len() as u64).saturating_mul(bits.into());
63 let big_digits = Integer::div_ceil(&total_bits, &big_digit::BITS.into())
64 .to_usize()
65 .unwrap_or(core::usize::MAX);
66 let mut data = Vec::with_capacity(big_digits);
67
68 let mut d = 0;
69 let mut dbits = 0; for &c in v {
74 d |= BigDigit::from(c) << dbits;
75 dbits += bits;
76
77 if dbits >= big_digit::BITS {
78 data.push(d);
79 dbits -= big_digit::BITS;
80 d = BigDigit::from(c) >> (bits - dbits);
83 }
84 }
85
86 if dbits > 0 {
87 debug_assert!(dbits < big_digit::BITS);
88 data.push(d as BigDigit);
89 }
90
91 biguint_from_vec(data)
92}
93
94pub(super) fn from_radix_be(buf: &[u8], radix: u32) -> Option<BigUint> {
95 assert!(2 <= radix && radix <= 256, "The radix must be within 2...256");
96 assert!(radix.is_power_of_two(), "The radix must be a power of 2");
97
98 if buf.is_empty() {
99 return Some(Zero::zero());
100 }
101
102 if radix != 256 && buf.iter().any(|&b| b >= radix as u8) {
103 return None;
104 }
105
106 let res = {
107 let bits = ilog2(radix);
109 let mut v = Vec::from(buf);
110 v.reverse();
111 if big_digit::BITS % bits == 0 {
112 from_bitwise_digits_le(&v, bits)
113 } else {
114 from_inexact_bitwise_digits_le(&v, bits)
115 }
116 };
117
118 Some(res)
119}
120
121pub(super) fn from_radix_le(buf: &[u8], radix: u32) -> Option<BigUint> {
122 assert!(2 <= radix && radix <= 256, "The radix must be within 2...256");
123 assert!(radix.is_power_of_two(), "The radix must be a power of 2");
124
125 if buf.is_empty() {
126 return Some(Zero::zero());
127 }
128
129 if radix != 256 && buf.iter().any(|&b| b >= radix as u8) {
130 return None;
131 }
132
133 let res = {
134 let bits = ilog2(radix);
136 if big_digit::BITS % bits == 0 {
137 from_bitwise_digits_le(buf, bits)
138 } else {
139 from_inexact_bitwise_digits_le(buf, bits)
140 }
141 };
142
143 Some(res)
144}
145
146impl Num for BigUint {
147 type FromStrRadixErr = ParseBigIntError;
148
149 fn from_str_radix(s: &str, radix: u32) -> Result<BigUint, ParseBigIntError> {
151 assert!(2 <= radix && radix <= 36, "The radix must be within 2...36");
152 assert!(radix.is_power_of_two(), "The radix must be a power of 2");
153
154 let mut s = s;
155 if s.starts_with('+') {
156 let tail = &s[1..];
157 if !tail.starts_with('+') {
158 s = tail
159 }
160 }
161
162 if s.is_empty() {
163 return Err(ParseBigIntError::empty());
164 }
165
166 if s.starts_with('_') {
167 return Err(ParseBigIntError::invalid());
169 }
170
171 let mut v = Vec::with_capacity(s.len());
173 for b in s.bytes() {
174 let d = match b {
175 b'0'..=b'9' => b - b'0',
176 b'a'..=b'z' => b - b'a' + 10,
177 b'A'..=b'Z' => b - b'A' + 10,
178 b'_' => continue,
179 _ => core::u8::MAX,
180 };
181 if d < radix as u8 {
182 v.push(d);
183 } else {
184 return Err(ParseBigIntError::invalid());
185 }
186 }
187
188 let res = {
189 let bits = ilog2(radix);
191 v.reverse();
192 if big_digit::BITS % bits == 0 {
193 from_bitwise_digits_le(&v, bits)
194 } else {
195 from_inexact_bitwise_digits_le(&v, bits)
196 }
197 };
198 Ok(res)
199 }
200}
201
202impl ToPrimitive for BigUint {
203 #[inline]
204 fn to_i64(&self) -> Option<i64> {
205 self.to_u64().as_ref().and_then(u64::to_i64)
206 }
207
208 #[inline]
209 fn to_i128(&self) -> Option<i128> {
210 self.to_u128().as_ref().and_then(u128::to_i128)
211 }
212
213 #[allow(clippy::useless_conversion)]
214 #[inline]
215 fn to_u64(&self) -> Option<u64> {
216 let mut ret: u64 = 0;
217 let mut bits = 0;
218
219 for i in self.data.iter() {
220 if bits >= 64 {
221 return None;
222 }
223
224 ret += u64::from(*i) << bits;
226 bits += big_digit::BITS;
227 }
228
229 Some(ret)
230 }
231
232 #[inline]
233 fn to_u128(&self) -> Option<u128> {
234 let mut ret: u128 = 0;
235 let mut bits = 0;
236
237 for i in self.data.iter() {
238 if bits >= 128 {
239 return None;
240 }
241
242 ret |= u128::from(*i) << bits;
243 bits += big_digit::BITS;
244 }
245
246 Some(ret)
247 }
248}
249
250macro_rules! impl_try_from_biguint {
251 ($T:ty, $to_ty:path) => {
252 #[cfg(has_try_from)]
253 impl TryFrom<&BigUint> for $T {
254 type Error = TryFromBigIntError<()>;
255
256 #[inline]
257 fn try_from(value: &BigUint) -> Result<$T, TryFromBigIntError<()>> {
258 $to_ty(value).ok_or(TryFromBigIntError::new(()))
259 }
260 }
261
262 #[cfg(has_try_from)]
263 impl TryFrom<BigUint> for $T {
264 type Error = TryFromBigIntError<BigUint>;
265
266 #[inline]
267 fn try_from(value: BigUint) -> Result<$T, TryFromBigIntError<BigUint>> {
268 <$T>::try_from(&value).map_err(|_| TryFromBigIntError::new(value))
269 }
270 }
271 };
272}
273
274impl_try_from_biguint!(u8, ToPrimitive::to_u8);
275impl_try_from_biguint!(u16, ToPrimitive::to_u16);
276impl_try_from_biguint!(u32, ToPrimitive::to_u32);
277impl_try_from_biguint!(u64, ToPrimitive::to_u64);
278impl_try_from_biguint!(usize, ToPrimitive::to_usize);
279impl_try_from_biguint!(u128, ToPrimitive::to_u128);
280
281impl_try_from_biguint!(i8, ToPrimitive::to_i8);
282impl_try_from_biguint!(i16, ToPrimitive::to_i16);
283impl_try_from_biguint!(i32, ToPrimitive::to_i32);
284impl_try_from_biguint!(i64, ToPrimitive::to_i64);
285impl_try_from_biguint!(isize, ToPrimitive::to_isize);
286impl_try_from_biguint!(i128, ToPrimitive::to_i128);
287
288impl FromPrimitive for BigUint {
289 #[inline]
290 fn from_i64(n: i64) -> Option<BigUint> {
291 if n >= 0 {
292 Some(BigUint::from(n as u64))
293 } else {
294 None
295 }
296 }
297
298 #[inline]
299 fn from_i128(n: i128) -> Option<BigUint> {
300 if n >= 0 {
301 Some(BigUint::from(n as u128))
302 } else {
303 None
304 }
305 }
306
307 #[inline]
308 fn from_u64(n: u64) -> Option<BigUint> {
309 Some(BigUint::from(n))
310 }
311
312 #[inline]
313 fn from_u128(n: u128) -> Option<BigUint> {
314 Some(BigUint::from(n))
315 }
316}
317
318impl From<u64> for BigUint {
319 #[inline]
320 fn from(mut n: u64) -> Self {
321 let mut ret: BigUint = Zero::zero();
322
323 while n != 0 {
324 ret.data.push(n as BigDigit);
325 n = (n >> 1) >> (big_digit::BITS - 1);
327 }
328
329 ret
330 }
331}
332
333impl From<u128> for BigUint {
334 #[inline]
335 fn from(mut n: u128) -> Self {
336 let mut ret: BigUint = Zero::zero();
337
338 while n != 0 {
339 ret.data.push(n as BigDigit);
340 n >>= big_digit::BITS;
341 }
342
343 ret
344 }
345}
346
347macro_rules! impl_biguint_from_uint {
348 ($T:ty) => {
349 impl From<$T> for BigUint {
350 #[inline]
351 fn from(n: $T) -> Self {
352 BigUint::from(n as u64)
353 }
354 }
355 };
356}
357
358impl_biguint_from_uint!(u8);
359impl_biguint_from_uint!(u16);
360impl_biguint_from_uint!(u32);
361impl_biguint_from_uint!(usize);
362
363macro_rules! impl_biguint_try_from_int {
364 ($T:ty, $from_ty:path) => {
365 #[cfg(has_try_from)]
366 impl TryFrom<$T> for BigUint {
367 type Error = TryFromBigIntError<()>;
368
369 #[inline]
370 fn try_from(value: $T) -> Result<BigUint, TryFromBigIntError<()>> {
371 $from_ty(value).ok_or(TryFromBigIntError::new(()))
372 }
373 }
374 };
375}
376
377impl_biguint_try_from_int!(i8, FromPrimitive::from_i8);
378impl_biguint_try_from_int!(i16, FromPrimitive::from_i16);
379impl_biguint_try_from_int!(i32, FromPrimitive::from_i32);
380impl_biguint_try_from_int!(i64, FromPrimitive::from_i64);
381impl_biguint_try_from_int!(isize, FromPrimitive::from_isize);
382impl_biguint_try_from_int!(i128, FromPrimitive::from_i128);
383
384impl ToBigUint for BigUint {
385 #[inline]
386 fn to_biguint(&self) -> Option<BigUint> {
387 Some(self.clone())
388 }
389}
390
391macro_rules! impl_to_biguint {
392 ($T:ty, $from_ty:path) => {
393 impl ToBigUint for $T {
394 #[inline]
395 fn to_biguint(&self) -> Option<BigUint> {
396 $from_ty(*self)
397 }
398 }
399 };
400}
401
402impl_to_biguint!(isize, FromPrimitive::from_isize);
403impl_to_biguint!(i8, FromPrimitive::from_i8);
404impl_to_biguint!(i16, FromPrimitive::from_i16);
405impl_to_biguint!(i32, FromPrimitive::from_i32);
406impl_to_biguint!(i64, FromPrimitive::from_i64);
407impl_to_biguint!(i128, FromPrimitive::from_i128);
408
409impl_to_biguint!(usize, FromPrimitive::from_usize);
410impl_to_biguint!(u8, FromPrimitive::from_u8);
411impl_to_biguint!(u16, FromPrimitive::from_u16);
412impl_to_biguint!(u32, FromPrimitive::from_u32);
413impl_to_biguint!(u64, FromPrimitive::from_u64);
414impl_to_biguint!(u128, FromPrimitive::from_u128);
415
416pub(super) fn to_bitwise_digits_le(u: &BigUint, bits: u8) -> Vec<u8> {
418 debug_assert!(!u.is_zero() && bits <= 8 && big_digit::BITS % bits == 0);
419
420 let last_i = u.data.len() - 1;
421 let mask: BigDigit = (1 << bits) - 1;
422 let digits_per_big_digit = big_digit::BITS / bits;
423 let digits = Integer::div_ceil(&u.bits(), &u64::from(bits))
424 .to_usize()
425 .unwrap_or(core::usize::MAX);
426 let mut res = Vec::with_capacity(digits);
427
428 for mut r in u.data[..last_i].iter().cloned() {
429 for _ in 0..digits_per_big_digit {
430 res.push((r & mask) as u8);
431 r >>= bits;
432 }
433 }
434
435 let mut r = u.data[last_i];
436 while r != 0 {
437 res.push((r & mask) as u8);
438 r >>= bits;
439 }
440
441 res
442}
443
444fn to_inexact_bitwise_digits_le(u: &BigUint, bits: u8) -> Vec<u8> {
446 debug_assert!(!u.is_zero() && bits <= 8 && big_digit::BITS % bits != 0);
447
448 let mask: BigDigit = (1 << bits) - 1;
449 let digits = Integer::div_ceil(&u.bits(), &u64::from(bits))
450 .to_usize()
451 .unwrap_or(core::usize::MAX);
452 let mut res = Vec::with_capacity(digits);
453
454 let mut r = 0;
455 let mut rbits = 0;
456
457 for c in &u.data {
458 r |= *c << rbits;
459 rbits += big_digit::BITS;
460
461 while rbits >= bits {
462 res.push((r & mask) as u8);
463 r >>= bits;
464
465 if rbits > big_digit::BITS {
467 r = *c >> (big_digit::BITS - (rbits - bits));
468 }
469
470 rbits -= bits;
471 }
472 }
473
474 if rbits != 0 {
475 res.push(r as u8);
476 }
477
478 while let Some(&0) = res.last() {
479 res.pop();
480 }
481
482 res
483}
484
485pub(super) fn to_radix_le(u: &BigUint, radix: u32) -> Vec<u8> {
486 assert!(radix.is_power_of_two(), "The radix must be a power of 2");
487 if u.is_zero() {
488 vec![0]
489 } else {
490 let bits = ilog2(radix);
492 if big_digit::BITS % bits == 0 {
493 to_bitwise_digits_le(u, bits)
494 } else {
495 to_inexact_bitwise_digits_le(u, bits)
496 }
497 }
498}
499
500pub(crate) fn to_str_radix_reversed(u: &BigUint, radix: u32) -> Vec<u8> {
501 assert!(2 <= radix && radix <= 36, "The radix must be within 2...36");
502
503 if u.is_zero() {
504 return vec![b'0'];
505 }
506
507 let mut res = to_radix_le(u, radix);
508
509 for r in &mut res {
511 debug_assert!(u32::from(*r) < radix);
512 if *r < 10 {
513 *r += b'0';
514 } else {
515 *r += b'a' - 10;
516 }
517 }
518 res
519}