1use crate::Uint;
35use core::{fmt, fmt::Debug};
36
37#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
39pub enum ToUintError<T> {
40 ValueTooLarge(usize, T),
44
45 ValueNegative(usize, T),
49
50 NotANumber(usize),
52}
53
54#[cfg(feature = "std")]
55impl<T: fmt::Debug> std::error::Error for ToUintError<T> {}
56
57impl<T> fmt::Display for ToUintError<T> {
58 #[inline]
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 match self {
61 Self::ValueTooLarge(bits, _) => write!(f, "Value is too large for Uint<{bits}>"),
62 Self::ValueNegative(bits, _) => {
63 write!(f, "Negative values cannot be represented as Uint<{bits}>")
64 }
65 Self::NotANumber(bits) => {
66 write!(
67 f,
68 "'Not a number' (NaN) cannot be represented as Uint<{bits}>"
69 )
70 }
71 }
72 }
73}
74
75#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::module_name_repetitions)]
78#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
79pub enum FromUintError<T> {
80 Overflow(usize, T, T),
85}
86
87#[cfg(feature = "std")]
88impl<T: fmt::Debug> std::error::Error for FromUintError<T> {}
89
90impl<T> fmt::Display for FromUintError<T> {
91 #[inline]
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 match self {
94 Self::Overflow(bits, ..) => write!(
95 f,
96 "Uint<{bits}> value is too large for {}",
97 core::any::type_name::<T>()
98 ),
99 }
100 }
101}
102
103#[allow(dead_code)] #[derive(Debug, Clone, Copy)]
106pub enum ToFieldError {
107 NotInField,
109}
110
111#[cfg(feature = "std")]
112impl std::error::Error for ToFieldError {}
113
114impl fmt::Display for ToFieldError {
115 #[inline]
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 match self {
118 Self::NotInField => {
119 f.write_str("Number is equal or larger than the target field modulus.")
120 }
121 }
122 }
123}
124
125impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
126 pub(crate) const fn const_from_u64(x: u64) -> Self {
131 if BITS == 0 || (BITS < 64 && x >= 1 << BITS) {
132 return Self::MAX;
133 }
134 let mut limbs = [0; LIMBS];
135 limbs[0] = x;
136 Self::from_limbs(limbs)
137 }
138
139 #[inline]
158 #[must_use]
159 #[track_caller]
160 pub fn from<T>(value: T) -> Self
161 where
162 Self: UintTryFrom<T>,
163 {
164 match Self::uint_try_from(value) {
165 Ok(n) => n,
166 Err(e) => panic!("Uint conversion error: {e}"),
167 }
168 }
169
170 #[inline]
187 #[must_use]
188 pub fn saturating_from<T>(value: T) -> Self
189 where
190 Self: UintTryFrom<T>,
191 {
192 match Self::uint_try_from(value) {
193 Ok(n) => n,
194 Err(ToUintError::ValueTooLarge(..)) => Self::MAX,
195 Err(ToUintError::ValueNegative(..) | ToUintError::NotANumber(_)) => Self::ZERO,
196 }
197 }
198
199 #[inline]
216 #[must_use]
217 pub fn wrapping_from<T>(value: T) -> Self
218 where
219 Self: UintTryFrom<T>,
220 {
221 match Self::uint_try_from(value) {
222 Ok(n) | Err(ToUintError::ValueTooLarge(_, n) | ToUintError::ValueNegative(_, n)) => n,
223 Err(ToUintError::NotANumber(_)) => Self::ZERO,
224 }
225 }
226
227 #[inline]
242 #[must_use]
243 #[track_caller]
244 pub fn to<T>(&self) -> T
245 where
246 Self: UintTryTo<T>,
247 T: Debug,
248 {
249 self.uint_try_to().expect("Uint conversion error")
250 }
251
252 #[inline]
263 #[must_use]
264 pub fn wrapping_to<T>(&self) -> T
265 where
266 Self: UintTryTo<T>,
267 {
268 match self.uint_try_to() {
269 Ok(n) | Err(FromUintError::Overflow(_, n, _)) => n,
270 }
271 }
272
273 #[inline]
284 #[must_use]
285 pub fn saturating_to<T>(&self) -> T
286 where
287 Self: UintTryTo<T>,
288 {
289 match self.uint_try_to() {
290 Ok(n) | Err(FromUintError::Overflow(_, _, n)) => n,
291 }
292 }
293
294 #[inline]
300 #[doc(hidden)]
301 #[must_use]
302 #[track_caller]
303 #[deprecated(since = "1.4.0", note = "Use `::from()` instead.")]
304 pub fn from_uint<const BITS_SRC: usize, const LIMBS_SRC: usize>(
305 value: Uint<BITS_SRC, LIMBS_SRC>,
306 ) -> Self {
307 Self::from_limbs_slice(value.as_limbs())
308 }
309
310 #[inline]
311 #[doc(hidden)]
312 #[must_use]
313 #[deprecated(since = "1.4.0", note = "Use `::checked_from()` instead.")]
314 pub fn checked_from_uint<const BITS_SRC: usize, const LIMBS_SRC: usize>(
315 value: Uint<BITS_SRC, LIMBS_SRC>,
316 ) -> Option<Self> {
317 Self::checked_from_limbs_slice(value.as_limbs())
318 }
319
320 #[inline]
322 fn gt_u64_max(&self) -> bool {
323 self.limbs_gt(1)
324 }
325
326 #[inline]
328 fn gt_u128_max(&self) -> bool {
329 self.limbs_gt(2)
330 }
331
332 #[inline]
334 fn limbs_gt(&self, n: usize) -> bool {
335 if LIMBS < n {
336 return false;
337 }
338
339 if BITS <= 512 {
340 self.as_limbs()[n..]
342 .iter()
343 .copied()
344 .fold(0u64, core::ops::BitOr::bitor)
345 != 0
346 } else {
347 self.bit_len() > 64 * n
348 }
349 }
350}
351
352#[allow(clippy::module_name_repetitions)]
360pub trait UintTryFrom<T>: Sized {
361 #[doc(hidden)]
362 fn uint_try_from(value: T) -> Result<Self, ToUintError<Self>>;
363}
364
365impl<const BITS: usize, const LIMBS: usize, T> UintTryFrom<T> for Uint<BITS, LIMBS>
367where
368 Self: TryFrom<T, Error = ToUintError<Self>>,
369{
370 #[inline]
371 fn uint_try_from(value: T) -> Result<Self, ToUintError<Self>> {
372 Self::try_from(value)
373 }
374}
375
376impl<const BITS: usize, const LIMBS: usize, const BITS_SRC: usize, const LIMBS_SRC: usize>
377 UintTryFrom<Uint<BITS_SRC, LIMBS_SRC>> for Uint<BITS, LIMBS>
378{
379 #[inline]
380 fn uint_try_from(value: Uint<BITS_SRC, LIMBS_SRC>) -> Result<Self, ToUintError<Self>> {
381 let (n, overflow) = Self::overflowing_from_limbs_slice(value.as_limbs());
382 if overflow {
383 Err(ToUintError::ValueTooLarge(BITS, n))
384 } else {
385 Ok(n)
386 }
387 }
388}
389
390pub trait UintTryTo<T>: Sized {
393 #[doc(hidden)]
394 fn uint_try_to(&self) -> Result<T, FromUintError<T>>;
395}
396
397impl<const BITS: usize, const LIMBS: usize, T> UintTryTo<T> for Uint<BITS, LIMBS>
398where
399 T: for<'a> TryFrom<&'a Self, Error = FromUintError<T>>,
400{
401 #[inline]
402 fn uint_try_to(&self) -> Result<T, FromUintError<T>> {
403 T::try_from(self)
404 }
405}
406
407impl<const BITS: usize, const LIMBS: usize, const BITS_DST: usize, const LIMBS_DST: usize>
408 UintTryTo<Uint<BITS_DST, LIMBS_DST>> for Uint<BITS, LIMBS>
409{
410 #[inline]
411 fn uint_try_to(
412 &self,
413 ) -> Result<Uint<BITS_DST, LIMBS_DST>, FromUintError<Uint<BITS_DST, LIMBS_DST>>> {
414 let (n, overflow) = Uint::overflowing_from_limbs_slice(self.as_limbs());
415 if overflow {
416 Err(FromUintError::Overflow(BITS_DST, n, Uint::MAX))
417 } else {
418 Ok(n)
419 }
420 }
421}
422
423impl<const BITS: usize, const LIMBS: usize> TryFrom<u64> for Uint<BITS, LIMBS> {
425 type Error = ToUintError<Self>;
426
427 #[inline]
428 fn try_from(value: u64) -> Result<Self, Self::Error> {
429 match LIMBS {
430 0 | 1 if value > Self::MASK => {
431 return Err(ToUintError::ValueTooLarge(
432 BITS,
433 Self::from_limbs([value & Self::MASK; LIMBS]),
434 ))
435 }
436 0 => return Ok(Self::ZERO),
437 _ => {}
438 }
439 let mut limbs = [0; LIMBS];
440 limbs[0] = value;
441 Ok(Self::from_limbs(limbs))
442 }
443}
444
445impl<const BITS: usize, const LIMBS: usize> TryFrom<u128> for Uint<BITS, LIMBS> {
447 type Error = ToUintError<Self>;
448
449 #[inline]
450 #[allow(clippy::cast_lossless)]
451 #[allow(clippy::cast_possible_truncation)]
452 fn try_from(value: u128) -> Result<Self, Self::Error> {
453 if value <= u64::MAX as u128 {
454 return Self::try_from(value as u64);
455 }
456 if LIMBS < 2 {
457 return Self::try_from(value as u64)
458 .and_then(|n| Err(ToUintError::ValueTooLarge(BITS, n)));
459 }
460 let mut limbs = [0; LIMBS];
461 limbs[0] = value as u64;
462 limbs[1] = (value >> 64) as u64;
463 if LIMBS == 2 && limbs[1] > Self::MASK {
464 limbs[1] &= Self::MASK;
465 Err(ToUintError::ValueTooLarge(BITS, Self::from_limbs(limbs)))
466 } else {
467 Ok(Self::from_limbs(limbs))
468 }
469 }
470}
471
472macro_rules! impl_from_unsigned_int {
474 ($uint:ty) => {
475 impl<const BITS: usize, const LIMBS: usize> TryFrom<$uint> for Uint<BITS, LIMBS> {
476 type Error = ToUintError<Self>;
477
478 #[inline]
479 fn try_from(value: $uint) -> Result<Self, Self::Error> {
480 Self::try_from(value as u64)
481 }
482 }
483 };
484}
485
486impl_from_unsigned_int!(bool);
487impl_from_unsigned_int!(u8);
488impl_from_unsigned_int!(u16);
489impl_from_unsigned_int!(u32);
490impl_from_unsigned_int!(usize);
491
492macro_rules! impl_from_signed_int {
495 ($int:ty, $uint:ty) => {
496 impl<const BITS: usize, const LIMBS: usize> TryFrom<$int> for Uint<BITS, LIMBS> {
497 type Error = ToUintError<Self>;
498
499 #[inline]
500 fn try_from(value: $int) -> Result<Self, Self::Error> {
501 if value.is_negative() {
502 Err(match Self::try_from(value as $uint) {
503 Ok(n) | Err(ToUintError::ValueTooLarge(_, n)) => {
504 ToUintError::ValueNegative(BITS, n)
505 }
506 _ => unreachable!(),
507 })
508 } else {
509 Self::try_from(value as $uint)
510 }
511 }
512 }
513 };
514}
515
516impl_from_signed_int!(i8, u8);
517impl_from_signed_int!(i16, u16);
518impl_from_signed_int!(i32, u32);
519impl_from_signed_int!(i64, u64);
520impl_from_signed_int!(i128, u128);
521impl_from_signed_int!(isize, usize);
522
523#[cfg(feature = "std")]
524impl<const BITS: usize, const LIMBS: usize> TryFrom<f64> for Uint<BITS, LIMBS> {
525 type Error = ToUintError<Self>;
526
527 #[inline]
529 fn try_from(value: f64) -> Result<Self, Self::Error> {
530 if value.is_nan() {
531 return Err(ToUintError::NotANumber(BITS));
532 }
533 if value < 0.0 {
534 let wrapped = match Self::try_from(value.abs()) {
535 Ok(n) | Err(ToUintError::ValueTooLarge(_, n)) => n,
536 _ => Self::ZERO,
537 }
538 .wrapping_neg();
539 return Err(ToUintError::ValueNegative(BITS, wrapped));
540 }
541 #[allow(clippy::cast_precision_loss)] let modulus = (Self::BITS as f64).exp2();
543 if value >= modulus {
544 let wrapped = match Self::try_from(value % modulus) {
545 Ok(n) | Err(ToUintError::ValueTooLarge(_, n)) => n,
546 _ => Self::ZERO,
547 };
548 return Err(ToUintError::ValueTooLarge(BITS, wrapped)); }
550 if value < 0.5 {
551 return Ok(Self::ZERO);
552 }
553 assert!(value.is_normal());
555
556 let value = value + 0.5;
558
559 let bits = value.to_bits();
562 let sign = bits >> 63;
563 assert!(sign == 0);
564 let biased_exponent = (bits >> 52) & 0x7ff;
565 assert!(biased_exponent >= 1023);
566 let exponent = biased_exponent - 1023;
567 let fraction = bits & 0x000f_ffff_ffff_ffff;
568 let mantissa = 0x0010_0000_0000_0000 | fraction;
569
570 #[allow(clippy::cast_possible_truncation)] if exponent as usize > Self::BITS + 52 {
573 return Err(ToUintError::ValueTooLarge(BITS, Self::ZERO));
575 }
576 if exponent <= 52 {
577 Self::try_from(mantissa >> (52 - exponent))
579 } else {
580 #[allow(clippy::cast_possible_truncation)] let exponent = exponent as usize - 52;
582 let n = Self::try_from(mantissa)?;
583 let (n, overflow) = n.overflowing_shl(exponent);
584 if overflow {
585 Err(ToUintError::ValueTooLarge(BITS, n))
586 } else {
587 Ok(n)
588 }
589 }
590 }
591}
592
593#[cfg(feature = "std")]
594impl<const BITS: usize, const LIMBS: usize> TryFrom<f32> for Uint<BITS, LIMBS> {
595 type Error = ToUintError<Self>;
596
597 #[inline]
598 fn try_from(value: f32) -> Result<Self, Self::Error> {
599 #[allow(clippy::cast_lossless)]
600 Self::try_from(value as f64)
601 }
602}
603
604macro_rules! to_value_to_ref {
608 ($t:ty) => {
609 impl<const BITS: usize, const LIMBS: usize> TryFrom<Uint<BITS, LIMBS>> for $t {
610 type Error = FromUintError<Self>;
611
612 #[inline]
613 fn try_from(value: Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
614 Self::try_from(&value)
615 }
616 }
617 };
618}
619
620to_value_to_ref!(bool);
621
622impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for bool {
623 type Error = FromUintError<Self>;
624
625 #[inline]
626 fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
627 if BITS == 0 {
628 return Ok(false);
629 }
630 if value.gt_u64_max() || value.limbs[0] > 1 {
631 return Err(Self::Error::Overflow(BITS, value.bit(0), true));
632 }
633 Ok(value.limbs[0] != 0)
634 }
635}
636
637macro_rules! to_int {
638 ($($int:ty)*) => {$(
639 to_value_to_ref!($int);
640
641 impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for $int {
642 type Error = FromUintError<Self>;
643
644 #[inline]
645 #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
646 fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
647 if BITS == 0 {
648 return Ok(0);
649 }
650 if value.gt_u64_max() || value.limbs[0] > (Self::MAX as u64) {
651 return Err(Self::Error::Overflow(
652 BITS,
653 value.limbs[0] as Self,
654 Self::MAX,
655 ));
656 }
657 Ok(value.limbs[0] as Self)
658 }
659 }
660 )*};
661}
662
663to_int!(i8 u8 i16 u16 i32 u32 i64 u64 isize usize);
664
665to_value_to_ref!(i128);
666
667impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for i128 {
668 type Error = FromUintError<Self>;
669
670 #[inline]
671 #[allow(clippy::cast_possible_wrap)] #[allow(clippy::cast_lossless)] #[allow(clippy::use_self)] fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
675 if BITS <= 64 {
676 return Ok(u64::try_from(value).unwrap().into());
677 }
678 let result = value.as_double_words()[0].get();
679 if value.gt_u128_max() || result > i128::MAX as u128 {
680 return Err(Self::Error::Overflow(BITS, result as i128, i128::MAX));
681 }
682 Ok(result as i128)
683 }
684}
685
686to_value_to_ref!(u128);
687
688impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for u128 {
689 type Error = FromUintError<Self>;
690
691 #[inline]
692 #[allow(clippy::cast_lossless)] #[allow(clippy::use_self)] fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
695 if BITS <= 64 {
696 return Ok(u64::try_from(value).unwrap().into());
697 }
698 let result = value.as_double_words()[0].get();
699 if value.gt_u128_max() {
700 return Err(Self::Error::Overflow(BITS, result, u128::MAX));
701 }
702 Ok(result)
703 }
704}
705
706#[cfg(feature = "std")]
709impl<const BITS: usize, const LIMBS: usize> From<Uint<BITS, LIMBS>> for f32 {
710 #[inline]
711 fn from(value: Uint<BITS, LIMBS>) -> Self {
712 Self::from(&value)
713 }
714}
715
716#[cfg(feature = "std")]
717impl<const BITS: usize, const LIMBS: usize> From<&Uint<BITS, LIMBS>> for f32 {
718 #[inline]
722 #[allow(clippy::cast_precision_loss)] fn from(value: &Uint<BITS, LIMBS>) -> Self {
724 let (bits, exponent) = value.most_significant_bits();
725 (bits as Self) * (exponent as Self).exp2()
726 }
727}
728
729#[cfg(feature = "std")]
730impl<const BITS: usize, const LIMBS: usize> From<Uint<BITS, LIMBS>> for f64 {
731 #[inline]
732 fn from(value: Uint<BITS, LIMBS>) -> Self {
733 Self::from(&value)
734 }
735}
736
737#[cfg(feature = "std")]
738impl<const BITS: usize, const LIMBS: usize> From<&Uint<BITS, LIMBS>> for f64 {
739 #[inline]
743 #[allow(clippy::cast_precision_loss)] fn from(value: &Uint<BITS, LIMBS>) -> Self {
745 let (bits, exponent) = value.most_significant_bits();
746 (bits as Self) * (exponent as Self).exp2()
747 }
748}
749
750#[cfg(test)]
751mod test {
752 use super::*;
753 use crate::{const_for, nlimbs};
754
755 #[test]
756 fn test_u64() {
757 assert_eq!(Uint::<0, 0>::try_from(0_u64), Ok(Uint::ZERO));
758 assert_eq!(
759 Uint::<0, 0>::try_from(1_u64),
760 Err(ToUintError::ValueTooLarge(0, Uint::ZERO))
761 );
762 const_for!(BITS in NON_ZERO {
763 const LIMBS: usize = nlimbs(BITS);
764 assert_eq!(Uint::<BITS, LIMBS>::try_from(0_u64), Ok(Uint::ZERO));
765 assert_eq!(Uint::<BITS, LIMBS>::try_from(1_u64).unwrap().as_limbs()[0], 1);
766 });
767 }
768
769 #[test]
770 fn test_u64_max() {
771 assert_eq!(
772 Uint::<64, 1>::try_from(u64::MAX),
773 Ok(Uint::from_limbs([u64::MAX]))
774 );
775 assert_eq!(
776 Uint::<64, 1>::try_from(u64::MAX as u128),
777 Ok(Uint::from_limbs([u64::MAX]))
778 );
779 assert_eq!(
780 Uint::<64, 1>::try_from(u64::MAX as u128 + 1),
781 Err(ToUintError::ValueTooLarge(64, Uint::ZERO))
782 );
783
784 assert_eq!(
785 Uint::<128, 2>::try_from(u64::MAX),
786 Ok(Uint::from_limbs([u64::MAX, 0]))
787 );
788 assert_eq!(
789 Uint::<128, 2>::try_from(u64::MAX as u128),
790 Ok(Uint::from_limbs([u64::MAX, 0]))
791 );
792 assert_eq!(
793 Uint::<128, 2>::try_from(u64::MAX as u128 + 1),
794 Ok(Uint::from_limbs([0, 1]))
795 );
796 }
797
798 #[test]
799 fn test_u65() {
800 let x = uint!(18446744073711518810_U65);
801 assert_eq!(x.bit_len(), 65);
802 assert_eq!(
803 u64::try_from(x),
804 Err(FromUintError::Overflow(65, 1967194, u64::MAX))
805 );
806 }
807
808 #[test]
809 #[cfg(feature = "std")]
810 fn test_f64() {
811 assert_eq!(Uint::<0, 0>::try_from(0.0_f64), Ok(Uint::ZERO));
812 const_for!(BITS in NON_ZERO {
813 const LIMBS: usize = nlimbs(BITS);
814 assert_eq!(Uint::<BITS, LIMBS>::try_from(0.0_f64), Ok(Uint::ZERO));
815 assert_eq!(Uint::<BITS, LIMBS>::try_from(1.0_f64).unwrap().as_limbs()[0], 1);
816 });
817 assert_eq!(
818 Uint::<7, 1>::try_from(123.499_f64),
819 Ok(Uint::from_limbs([123]))
820 );
821 assert_eq!(
822 Uint::<7, 1>::try_from(123.500_f64),
823 Ok(Uint::from_limbs([124]))
824 );
825 }
826}