1use crate::{
4 arch::word::Word,
5 buffer::Buffer,
6 error::OutOfBoundsError,
7 ibig::IBig,
8 primitive::{self, PrimitiveSigned, PrimitiveUnsigned, WORD_BITS, WORD_BYTES},
9 sign::Sign::*,
10 ubig::{Repr::*, UBig},
11};
12use alloc::vec::Vec;
13use core::convert::{TryFrom, TryInto};
14
15impl Default for UBig {
16 #[inline]
18 fn default() -> UBig {
19 UBig::from_word(0)
20 }
21}
22
23impl Default for IBig {
24 #[inline]
26 fn default() -> IBig {
27 IBig::from(0u8)
28 }
29}
30
31impl UBig {
32 #[inline]
41 pub fn from_le_bytes(bytes: &[u8]) -> UBig {
42 if bytes.len() <= WORD_BYTES {
43 UBig::from_word(primitive::word_from_le_bytes_partial(bytes))
45 } else {
46 UBig::from_le_bytes_large(bytes)
47 }
48 }
49
50 fn from_le_bytes_large(bytes: &[u8]) -> UBig {
51 debug_assert!(bytes.len() > WORD_BYTES);
52 let mut buffer = Buffer::allocate((bytes.len() - 1) / WORD_BYTES + 1);
53 let mut chunks = bytes.chunks_exact(WORD_BYTES);
54 for chunk in &mut chunks {
55 buffer.push(Word::from_le_bytes(chunk.try_into().unwrap()));
56 }
57 if !chunks.remainder().is_empty() {
58 buffer.push(primitive::word_from_le_bytes_partial(chunks.remainder()));
59 }
60 buffer.into()
61 }
62
63 #[inline]
72 pub fn from_be_bytes(bytes: &[u8]) -> UBig {
73 if bytes.len() <= WORD_BYTES {
74 UBig::from_word(primitive::word_from_be_bytes_partial(bytes))
76 } else {
77 UBig::from_be_bytes_large(bytes)
78 }
79 }
80
81 fn from_be_bytes_large(bytes: &[u8]) -> UBig {
82 debug_assert!(bytes.len() > WORD_BYTES);
83 let mut buffer = Buffer::allocate((bytes.len() - 1) / WORD_BYTES + 1);
84 let mut chunks = bytes.rchunks_exact(WORD_BYTES);
85 for chunk in &mut chunks {
86 buffer.push(Word::from_be_bytes(chunk.try_into().unwrap()));
87 }
88 if !chunks.remainder().is_empty() {
89 buffer.push(primitive::word_from_be_bytes_partial(chunks.remainder()));
90 }
91 buffer.into()
92 }
93
94 pub fn to_le_bytes(&self) -> Vec<u8> {
104 match self.repr() {
105 Small(x) => {
106 let bytes = x.to_le_bytes();
107 let skip_bytes = x.leading_zeros() as usize / 8;
108 bytes[..WORD_BYTES - skip_bytes].to_vec()
109 }
110 Large(buffer) => {
111 let n = buffer.len();
112 let last = buffer[n - 1];
113 let skip_last_bytes = last.leading_zeros() as usize / 8;
114 let mut bytes = Vec::with_capacity(n * WORD_BYTES - skip_last_bytes);
115 for word in &buffer[..n - 1] {
116 bytes.extend_from_slice(&word.to_le_bytes());
117 }
118 let last_bytes = last.to_le_bytes();
119 bytes.extend_from_slice(&last_bytes[..WORD_BYTES - skip_last_bytes]);
120 bytes
121 }
122 }
123 }
124
125 pub fn to_be_bytes(&self) -> Vec<u8> {
135 match self.repr() {
136 Small(x) => {
137 let bytes = x.to_be_bytes();
138 let skip_bytes = x.leading_zeros() as usize / 8;
139 bytes[skip_bytes..].to_vec()
140 }
141 Large(buffer) => {
142 let n = buffer.len();
143 let last = buffer[n - 1];
144 let skip_last_bytes = last.leading_zeros() as usize / 8;
145 let mut bytes = Vec::with_capacity(n * WORD_BYTES - skip_last_bytes);
146 let last_bytes = last.to_be_bytes();
147 bytes.extend_from_slice(&last_bytes[skip_last_bytes..]);
148 for word in buffer[..n - 1].iter().rev() {
149 bytes.extend_from_slice(&word.to_be_bytes());
150 }
151 bytes
152 }
153 }
154 }
155
156 #[inline]
167 pub fn to_f32(&self) -> f32 {
168 match self.repr() {
169 Small(word) => *word as f32,
170 Large(_) => match u32::try_from(self) {
171 Ok(val) => val as f32,
172 Err(_) => self.to_f32_slow(),
173 },
174 }
175 }
176
177 fn to_f32_slow(&self) -> f32 {
178 let n = self.bit_len();
179 debug_assert!(n > 32);
180
181 if n > 128 {
182 f32::INFINITY
183 } else {
184 let exponent = (n - 1) as u32;
185 debug_assert!((32..128).contains(&exponent));
186 let mantissa25 = u32::try_from(self >> (n - 25)).unwrap();
187 let mantissa = mantissa25 >> 1;
188
189 let value = ((exponent + 126) << 23) + mantissa;
191
192 let extra_bit = self.are_low_bits_nonzero(n - 25);
194 let low_bits = ((mantissa25 & 0b11) << 1) | u32::from(extra_bit);
196 let adjustment = round_to_even_adjustment(low_bits);
197
198 let value = value + u32::from(adjustment);
203 f32::from_bits(value)
204 }
205 }
206
207 #[inline]
218 pub fn to_f64(&self) -> f64 {
219 match self.repr() {
220 Small(word) => *word as f64,
221 Large(_) => match u64::try_from(self) {
222 Ok(val) => val as f64,
223 Err(_) => self.to_f64_slow(),
224 },
225 }
226 }
227
228 fn to_f64_slow(&self) -> f64 {
229 let n = self.bit_len();
230 debug_assert!(n > 64);
231
232 if n > 1024 {
233 f64::INFINITY
234 } else {
235 let exponent = (n - 1) as u64;
236 debug_assert!((64..1024).contains(&exponent));
237 let mantissa54 = u64::try_from(self >> (n - 54)).unwrap();
238 let mantissa = mantissa54 >> 1;
239
240 let value = ((exponent + 1022) << 52) + mantissa;
242
243 let extra_bit = self.are_low_bits_nonzero(n - 54);
245 let low_bits = (((mantissa54 & 0b11) as u32) << 1) | u32::from(extra_bit);
247 let adjustment = round_to_even_adjustment(low_bits);
248
249 let value = value + u64::from(adjustment);
254 f64::from_bits(value)
255 }
256 }
257}
258
259impl IBig {
260 #[inline]
271 pub fn to_f32(&self) -> f32 {
272 let val = self.magnitude().to_f32();
273 match self.sign() {
274 Positive => val,
275 Negative => -val,
276 }
277 }
278
279 #[inline]
290 pub fn to_f64(&self) -> f64 {
291 let val = self.magnitude().to_f64();
292 match self.sign() {
293 Positive => val,
294 Negative => -val,
295 }
296 }
297}
298
299#[inline]
302fn round_to_even_adjustment(bits: u32) -> bool {
303 bits >= 0b110 || bits == 0b011
304}
305
306macro_rules! ubig_unsigned_conversions {
307 ($t:ty) => {
308 impl From<$t> for UBig {
309 #[inline]
310 fn from(value: $t) -> UBig {
311 UBig::from_unsigned(value)
312 }
313 }
314
315 impl TryFrom<UBig> for $t {
316 type Error = OutOfBoundsError;
317
318 #[inline]
319 fn try_from(value: UBig) -> Result<$t, OutOfBoundsError> {
320 value.try_to_unsigned()
321 }
322 }
323
324 impl TryFrom<&UBig> for $t {
325 type Error = OutOfBoundsError;
326
327 #[inline]
328 fn try_from(value: &UBig) -> Result<$t, OutOfBoundsError> {
329 value.try_to_unsigned()
330 }
331 }
332 };
333}
334
335ubig_unsigned_conversions!(u8);
336ubig_unsigned_conversions!(u16);
337ubig_unsigned_conversions!(u32);
338ubig_unsigned_conversions!(u64);
339ubig_unsigned_conversions!(u128);
340ubig_unsigned_conversions!(usize);
341
342impl From<bool> for UBig {
343 #[inline]
344 fn from(b: bool) -> UBig {
345 u8::from(b).into()
346 }
347}
348
349macro_rules! ubig_signed_conversions {
350 ($t:ty) => {
351 impl TryFrom<$t> for UBig {
352 type Error = OutOfBoundsError;
353
354 #[inline]
355 fn try_from(value: $t) -> Result<UBig, OutOfBoundsError> {
356 UBig::try_from_signed(value)
357 }
358 }
359
360 impl TryFrom<UBig> for $t {
361 type Error = OutOfBoundsError;
362
363 #[inline]
364 fn try_from(value: UBig) -> Result<$t, OutOfBoundsError> {
365 value.try_to_signed()
366 }
367 }
368
369 impl TryFrom<&UBig> for $t {
370 type Error = OutOfBoundsError;
371
372 #[inline]
373 fn try_from(value: &UBig) -> Result<$t, OutOfBoundsError> {
374 value.try_to_signed()
375 }
376 }
377 };
378}
379
380ubig_signed_conversions!(i8);
381ubig_signed_conversions!(i16);
382ubig_signed_conversions!(i32);
383ubig_signed_conversions!(i64);
384ubig_signed_conversions!(i128);
385ubig_signed_conversions!(isize);
386
387macro_rules! ibig_unsigned_conversions {
388 ($t:ty) => {
389 impl From<$t> for IBig {
390 #[inline]
391 fn from(value: $t) -> IBig {
392 IBig::from_unsigned(value)
393 }
394 }
395
396 impl TryFrom<IBig> for $t {
397 type Error = OutOfBoundsError;
398
399 #[inline]
400 fn try_from(value: IBig) -> Result<$t, OutOfBoundsError> {
401 value.try_to_unsigned()
402 }
403 }
404
405 impl TryFrom<&IBig> for $t {
406 type Error = OutOfBoundsError;
407
408 #[inline]
409 fn try_from(value: &IBig) -> Result<$t, OutOfBoundsError> {
410 value.try_to_unsigned()
411 }
412 }
413 };
414}
415
416ibig_unsigned_conversions!(u8);
417ibig_unsigned_conversions!(u16);
418ibig_unsigned_conversions!(u32);
419ibig_unsigned_conversions!(u64);
420ibig_unsigned_conversions!(u128);
421ibig_unsigned_conversions!(usize);
422
423impl From<bool> for IBig {
424 #[inline]
425 fn from(b: bool) -> IBig {
426 u8::from(b).into()
427 }
428}
429
430macro_rules! ibig_signed_conversions {
431 ($t:ty) => {
432 impl From<$t> for IBig {
433 #[inline]
434 fn from(value: $t) -> IBig {
435 IBig::from_signed(value)
436 }
437 }
438
439 impl TryFrom<IBig> for $t {
440 type Error = OutOfBoundsError;
441
442 #[inline]
443 fn try_from(value: IBig) -> Result<$t, OutOfBoundsError> {
444 value.try_to_signed()
445 }
446 }
447
448 impl TryFrom<&IBig> for $t {
449 type Error = OutOfBoundsError;
450
451 #[inline]
452 fn try_from(value: &IBig) -> Result<$t, OutOfBoundsError> {
453 value.try_to_signed()
454 }
455 }
456 };
457}
458
459ibig_signed_conversions!(i8);
460ibig_signed_conversions!(i16);
461ibig_signed_conversions!(i32);
462ibig_signed_conversions!(i64);
463ibig_signed_conversions!(i128);
464ibig_signed_conversions!(isize);
465
466impl From<UBig> for IBig {
467 #[inline]
468 fn from(x: UBig) -> IBig {
469 IBig::from_sign_magnitude(Positive, x)
470 }
471}
472
473impl From<&UBig> for IBig {
474 #[inline]
475 fn from(x: &UBig) -> IBig {
476 IBig::from(x.clone())
477 }
478}
479
480impl TryFrom<IBig> for UBig {
481 type Error = OutOfBoundsError;
482
483 #[inline]
484 fn try_from(x: IBig) -> Result<UBig, OutOfBoundsError> {
485 match x.into_sign_magnitude() {
486 (Positive, mag) => Ok(mag),
487 (Negative, _) => Err(OutOfBoundsError),
488 }
489 }
490}
491
492impl TryFrom<&IBig> for UBig {
493 type Error = OutOfBoundsError;
494
495 #[inline]
496 fn try_from(x: &IBig) -> Result<UBig, OutOfBoundsError> {
497 match x.sign() {
498 Positive => Ok(x.magnitude().clone()),
499 Negative => Err(OutOfBoundsError),
500 }
501 }
502}
503
504impl UBig {
505 #[inline]
507 pub(crate) fn from_unsigned<T>(x: T) -> UBig
508 where
509 T: PrimitiveUnsigned,
510 {
511 match x.try_into() {
512 Ok(w) => UBig::from_word(w),
513 Err(_) => {
514 let repr = x.to_le_bytes();
515 UBig::from_le_bytes(repr.as_ref())
516 }
517 }
518 }
519
520 #[inline]
522 fn try_from_signed<T>(x: T) -> Result<UBig, OutOfBoundsError>
523 where
524 T: PrimitiveSigned,
525 {
526 match T::Unsigned::try_from(x) {
527 Ok(u) => Ok(UBig::from_unsigned(u)),
528 Err(_) => Err(OutOfBoundsError),
529 }
530 }
531
532 #[inline]
534 pub(crate) fn try_to_unsigned<T>(&self) -> Result<T, OutOfBoundsError>
535 where
536 T: PrimitiveUnsigned,
537 {
538 match self.repr() {
539 Small(w) => match T::try_from(*w) {
540 Ok(val) => Ok(val),
541 Err(_) => Err(OutOfBoundsError),
542 },
543 Large(buffer) => unsigned_from_words(buffer),
544 }
545 }
546
547 #[inline]
549 fn try_to_signed<T>(&self) -> Result<T, OutOfBoundsError>
550 where
551 T: PrimitiveSigned,
552 {
553 match self.repr() {
554 Small(w) => T::try_from(*w).map_err(|_| OutOfBoundsError),
555 Large(buffer) => {
556 let u: T::Unsigned = unsigned_from_words(buffer)?;
557 u.try_into().map_err(|_| OutOfBoundsError)
558 }
559 }
560 }
561
562 #[inline]
563 pub(crate) fn from_ibig_panic_on_overflow(x: IBig) -> UBig {
564 match UBig::try_from(x) {
565 Ok(v) => v,
566 Err(_) => UBig::panic_negative(),
567 }
568 }
569
570 #[inline]
571 pub(crate) fn panic_negative() -> ! {
572 panic!("negative UBig")
573 }
574}
575
576fn unsigned_from_words<T>(words: &[Word]) -> Result<T, OutOfBoundsError>
578where
579 T: PrimitiveUnsigned,
580{
581 debug_assert!(words.len() >= 2);
582 let t_words = T::BYTE_SIZE / WORD_BYTES;
583 if t_words <= 1 || words.len() > t_words {
584 Err(OutOfBoundsError)
585 } else {
586 assert!(
587 T::BIT_SIZE % WORD_BITS == 0,
588 "A large primitive type not a multiple of word size."
589 );
590 let mut repr = T::default().to_le_bytes();
591 let bytes: &mut [u8] = repr.as_mut();
592 for (idx, w) in words.iter().enumerate() {
593 let pos = idx * WORD_BYTES;
594 bytes[pos..pos + WORD_BYTES].copy_from_slice(&w.to_le_bytes());
595 }
596 Ok(T::from_le_bytes(repr))
597 }
598}
599
600impl IBig {
601 #[inline]
603 pub(crate) fn from_unsigned<T: PrimitiveUnsigned>(x: T) -> IBig {
604 IBig::from(UBig::from_unsigned(x))
605 }
606
607 #[inline]
609 pub(crate) fn from_signed<T: PrimitiveSigned>(x: T) -> IBig {
610 let (sign, mag) = x.to_sign_magnitude();
611 IBig::from_sign_magnitude(sign, UBig::from_unsigned(mag))
612 }
613
614 #[inline]
616 pub(crate) fn try_to_unsigned<T: PrimitiveUnsigned>(&self) -> Result<T, OutOfBoundsError> {
617 match self.sign() {
618 Positive => self.magnitude().try_to_unsigned(),
619 Negative => Err(OutOfBoundsError),
620 }
621 }
622
623 #[inline]
625 pub(crate) fn try_to_signed<T: PrimitiveSigned>(&self) -> Result<T, OutOfBoundsError> {
626 let u: T::Unsigned = self.magnitude().try_to_unsigned()?;
627 T::try_from_sign_magnitude(self.sign(), u)
628 }
629}