1use super::Sign::{self, Minus, NoSign, Plus};
2use super::{BigInt, ToBigInt};
3
4use crate::TryFromBigIntError;
5use crate::{BigUint, ParseBigIntError, ToBigUint};
6
7use alloc::vec::Vec;
8use core::cmp::Ordering::{Equal, Greater, Less};
9use core::convert::TryFrom;
10use core::str::{self, FromStr};
11use num_traits::{FromPrimitive, Num, One, ToPrimitive, Zero};
12
13impl FromStr for BigInt {
14 type Err = ParseBigIntError;
15
16 #[inline]
17 fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
18 BigInt::from_str_radix(s, 10)
19 }
20}
21
22impl Num for BigInt {
23 type FromStrRadixErr = ParseBigIntError;
24
25 #[inline]
27 fn from_str_radix(mut s: &str, radix: u32) -> Result<BigInt, ParseBigIntError> {
28 let sign = if let Some(tail) = s.strip_prefix('-') {
29 if !tail.starts_with('+') {
30 s = tail
31 }
32 Minus
33 } else {
34 Plus
35 };
36 let bu = BigUint::from_str_radix(s, radix)?;
37 Ok(BigInt::from_biguint(sign, bu))
38 }
39}
40
41impl ToPrimitive for BigInt {
42 #[inline]
43 fn to_i64(&self) -> Option<i64> {
44 match self.sign {
45 Plus => self.data.to_i64(),
46 NoSign => Some(0),
47 Minus => {
48 let n = self.data.to_u64()?;
49 let m: u64 = 1 << 63;
50 match n.cmp(&m) {
51 Less => Some(-(n as i64)),
52 Equal => Some(i64::MIN),
53 Greater => None,
54 }
55 }
56 }
57 }
58
59 #[inline]
60 fn to_i128(&self) -> Option<i128> {
61 match self.sign {
62 Plus => self.data.to_i128(),
63 NoSign => Some(0),
64 Minus => {
65 let n = self.data.to_u128()?;
66 let m: u128 = 1 << 127;
67 match n.cmp(&m) {
68 Less => Some(-(n as i128)),
69 Equal => Some(i128::MIN),
70 Greater => None,
71 }
72 }
73 }
74 }
75
76 #[inline]
77 fn to_u64(&self) -> Option<u64> {
78 match self.sign {
79 Plus => self.data.to_u64(),
80 NoSign => Some(0),
81 Minus => None,
82 }
83 }
84
85 #[inline]
86 fn to_u128(&self) -> Option<u128> {
87 match self.sign {
88 Plus => self.data.to_u128(),
89 NoSign => Some(0),
90 Minus => None,
91 }
92 }
93
94 #[inline]
95 fn to_f32(&self) -> Option<f32> {
96 let n = self.data.to_f32()?;
97 Some(if self.sign == Minus { -n } else { n })
98 }
99
100 #[inline]
101 fn to_f64(&self) -> Option<f64> {
102 let n = self.data.to_f64()?;
103 Some(if self.sign == Minus { -n } else { n })
104 }
105}
106
107macro_rules! impl_try_from_bigint {
108 ($T:ty, $to_ty:path) => {
109 impl TryFrom<&BigInt> for $T {
110 type Error = TryFromBigIntError<()>;
111
112 #[inline]
113 fn try_from(value: &BigInt) -> Result<$T, TryFromBigIntError<()>> {
114 $to_ty(value).ok_or(TryFromBigIntError::new(()))
115 }
116 }
117
118 impl TryFrom<BigInt> for $T {
119 type Error = TryFromBigIntError<BigInt>;
120
121 #[inline]
122 fn try_from(value: BigInt) -> Result<$T, TryFromBigIntError<BigInt>> {
123 <$T>::try_from(&value).map_err(|_| TryFromBigIntError::new(value))
124 }
125 }
126 };
127}
128
129impl_try_from_bigint!(u8, ToPrimitive::to_u8);
130impl_try_from_bigint!(u16, ToPrimitive::to_u16);
131impl_try_from_bigint!(u32, ToPrimitive::to_u32);
132impl_try_from_bigint!(u64, ToPrimitive::to_u64);
133impl_try_from_bigint!(usize, ToPrimitive::to_usize);
134impl_try_from_bigint!(u128, ToPrimitive::to_u128);
135
136impl_try_from_bigint!(i8, ToPrimitive::to_i8);
137impl_try_from_bigint!(i16, ToPrimitive::to_i16);
138impl_try_from_bigint!(i32, ToPrimitive::to_i32);
139impl_try_from_bigint!(i64, ToPrimitive::to_i64);
140impl_try_from_bigint!(isize, ToPrimitive::to_isize);
141impl_try_from_bigint!(i128, ToPrimitive::to_i128);
142
143impl FromPrimitive for BigInt {
144 #[inline]
145 fn from_i64(n: i64) -> Option<BigInt> {
146 Some(BigInt::from(n))
147 }
148
149 #[inline]
150 fn from_i128(n: i128) -> Option<BigInt> {
151 Some(BigInt::from(n))
152 }
153
154 #[inline]
155 fn from_u64(n: u64) -> Option<BigInt> {
156 Some(BigInt::from(n))
157 }
158
159 #[inline]
160 fn from_u128(n: u128) -> Option<BigInt> {
161 Some(BigInt::from(n))
162 }
163
164 #[inline]
165 fn from_f64(n: f64) -> Option<BigInt> {
166 if n >= 0.0 {
167 BigUint::from_f64(n).map(BigInt::from)
168 } else {
169 let x = BigUint::from_f64(-n)?;
170 Some(-BigInt::from(x))
171 }
172 }
173}
174
175impl From<i64> for BigInt {
176 #[inline]
177 fn from(n: i64) -> Self {
178 if n >= 0 {
179 BigInt::from(n as u64)
180 } else {
181 let u = u64::MAX - (n as u64) + 1;
182 BigInt {
183 sign: Minus,
184 data: BigUint::from(u),
185 }
186 }
187 }
188}
189
190impl From<i128> for BigInt {
191 #[inline]
192 fn from(n: i128) -> Self {
193 if n >= 0 {
194 BigInt::from(n as u128)
195 } else {
196 let u = u128::MAX - (n as u128) + 1;
197 BigInt {
198 sign: Minus,
199 data: BigUint::from(u),
200 }
201 }
202 }
203}
204
205macro_rules! impl_bigint_from_int {
206 ($T:ty) => {
207 impl From<$T> for BigInt {
208 #[inline]
209 fn from(n: $T) -> Self {
210 BigInt::from(n as i64)
211 }
212 }
213 };
214}
215
216impl_bigint_from_int!(i8);
217impl_bigint_from_int!(i16);
218impl_bigint_from_int!(i32);
219impl_bigint_from_int!(isize);
220
221impl From<u64> for BigInt {
222 #[inline]
223 fn from(n: u64) -> Self {
224 if n > 0 {
225 BigInt {
226 sign: Plus,
227 data: BigUint::from(n),
228 }
229 } else {
230 Self::ZERO
231 }
232 }
233}
234
235impl From<u128> for BigInt {
236 #[inline]
237 fn from(n: u128) -> Self {
238 if n > 0 {
239 BigInt {
240 sign: Plus,
241 data: BigUint::from(n),
242 }
243 } else {
244 Self::ZERO
245 }
246 }
247}
248
249macro_rules! impl_bigint_from_uint {
250 ($T:ty) => {
251 impl From<$T> for BigInt {
252 #[inline]
253 fn from(n: $T) -> Self {
254 BigInt::from(n as u64)
255 }
256 }
257 };
258}
259
260impl_bigint_from_uint!(u8);
261impl_bigint_from_uint!(u16);
262impl_bigint_from_uint!(u32);
263impl_bigint_from_uint!(usize);
264
265impl From<BigUint> for BigInt {
266 #[inline]
267 fn from(n: BigUint) -> Self {
268 if n.is_zero() {
269 Self::ZERO
270 } else {
271 BigInt {
272 sign: Plus,
273 data: n,
274 }
275 }
276 }
277}
278
279impl ToBigInt for BigInt {
280 #[inline]
281 fn to_bigint(&self) -> Option<BigInt> {
282 Some(self.clone())
283 }
284}
285
286impl ToBigInt for BigUint {
287 #[inline]
288 fn to_bigint(&self) -> Option<BigInt> {
289 if self.is_zero() {
290 Some(BigInt::ZERO)
291 } else {
292 Some(BigInt {
293 sign: Plus,
294 data: self.clone(),
295 })
296 }
297 }
298}
299
300impl ToBigUint for BigInt {
301 #[inline]
302 fn to_biguint(&self) -> Option<BigUint> {
303 match self.sign() {
304 Plus => Some(self.data.clone()),
305 NoSign => Some(BigUint::ZERO),
306 Minus => None,
307 }
308 }
309}
310
311impl TryFrom<&BigInt> for BigUint {
312 type Error = TryFromBigIntError<()>;
313
314 #[inline]
315 fn try_from(value: &BigInt) -> Result<BigUint, TryFromBigIntError<()>> {
316 value
317 .to_biguint()
318 .ok_or_else(|| TryFromBigIntError::new(()))
319 }
320}
321
322impl TryFrom<BigInt> for BigUint {
323 type Error = TryFromBigIntError<BigInt>;
324
325 #[inline]
326 fn try_from(value: BigInt) -> Result<BigUint, TryFromBigIntError<BigInt>> {
327 if value.sign() == Sign::Minus {
328 Err(TryFromBigIntError::new(value))
329 } else {
330 Ok(value.data)
331 }
332 }
333}
334
335macro_rules! impl_to_bigint {
336 ($T:ty, $from_ty:path) => {
337 impl ToBigInt for $T {
338 #[inline]
339 fn to_bigint(&self) -> Option<BigInt> {
340 $from_ty(*self)
341 }
342 }
343 };
344}
345
346impl_to_bigint!(isize, FromPrimitive::from_isize);
347impl_to_bigint!(i8, FromPrimitive::from_i8);
348impl_to_bigint!(i16, FromPrimitive::from_i16);
349impl_to_bigint!(i32, FromPrimitive::from_i32);
350impl_to_bigint!(i64, FromPrimitive::from_i64);
351impl_to_bigint!(i128, FromPrimitive::from_i128);
352
353impl_to_bigint!(usize, FromPrimitive::from_usize);
354impl_to_bigint!(u8, FromPrimitive::from_u8);
355impl_to_bigint!(u16, FromPrimitive::from_u16);
356impl_to_bigint!(u32, FromPrimitive::from_u32);
357impl_to_bigint!(u64, FromPrimitive::from_u64);
358impl_to_bigint!(u128, FromPrimitive::from_u128);
359
360impl_to_bigint!(f32, FromPrimitive::from_f32);
361impl_to_bigint!(f64, FromPrimitive::from_f64);
362
363impl From<bool> for BigInt {
364 fn from(x: bool) -> Self {
365 if x {
366 One::one()
367 } else {
368 Self::ZERO
369 }
370 }
371}
372
373#[inline]
374pub(super) fn from_signed_bytes_be(digits: &[u8]) -> BigInt {
375 let sign = match digits.first() {
376 Some(v) if *v > 0x7f => Sign::Minus,
377 Some(_) => Sign::Plus,
378 None => return BigInt::ZERO,
379 };
380
381 if sign == Sign::Minus {
382 let mut digits = Vec::from(digits);
384 twos_complement_be(&mut digits);
385 BigInt::from_biguint(sign, BigUint::from_bytes_be(&digits))
386 } else {
387 BigInt::from_biguint(sign, BigUint::from_bytes_be(digits))
388 }
389}
390
391#[inline]
392pub(super) fn from_signed_bytes_le(digits: &[u8]) -> BigInt {
393 let sign = match digits.last() {
394 Some(v) if *v > 0x7f => Sign::Minus,
395 Some(_) => Sign::Plus,
396 None => return BigInt::ZERO,
397 };
398
399 if sign == Sign::Minus {
400 let mut digits = Vec::from(digits);
402 twos_complement_le(&mut digits);
403 BigInt::from_biguint(sign, BigUint::from_bytes_le(&digits))
404 } else {
405 BigInt::from_biguint(sign, BigUint::from_bytes_le(digits))
406 }
407}
408
409#[inline]
410pub(super) fn to_signed_bytes_be(x: &BigInt) -> Vec<u8> {
411 let mut bytes = x.data.to_bytes_be();
412 let first_byte = bytes.first().cloned().unwrap_or(0);
413 if first_byte > 0x7f
414 && !(first_byte == 0x80 && bytes.iter().skip(1).all(Zero::is_zero) && x.sign == Sign::Minus)
415 {
416 bytes.insert(0, 0);
418 }
419 if x.sign == Sign::Minus {
420 twos_complement_be(&mut bytes);
421 }
422 bytes
423}
424
425#[inline]
426pub(super) fn to_signed_bytes_le(x: &BigInt) -> Vec<u8> {
427 let mut bytes = x.data.to_bytes_le();
428 let last_byte = bytes.last().cloned().unwrap_or(0);
429 if last_byte > 0x7f
430 && !(last_byte == 0x80
431 && bytes.iter().rev().skip(1).all(Zero::is_zero)
432 && x.sign == Sign::Minus)
433 {
434 bytes.push(0);
436 }
437 if x.sign == Sign::Minus {
438 twos_complement_le(&mut bytes);
439 }
440 bytes
441}
442
443#[inline]
446fn twos_complement_le(digits: &mut [u8]) {
447 twos_complement(digits)
448}
449
450#[inline]
453fn twos_complement_be(digits: &mut [u8]) {
454 twos_complement(digits.iter_mut().rev())
455}
456
457#[inline]
460fn twos_complement<'a, I>(digits: I)
461where
462 I: IntoIterator<Item = &'a mut u8>,
463{
464 let mut carry = true;
465 for d in digits {
466 *d = !*d;
467 if carry {
468 *d = d.wrapping_add(1);
469 carry = d.is_zero();
470 }
471 }
472}