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
321#[allow(clippy::module_name_repetitions)]
329pub trait UintTryFrom<T>: Sized {
330 #[doc(hidden)]
331 fn uint_try_from(value: T) -> Result<Self, ToUintError<Self>>;
332}
333
334impl<const BITS: usize, const LIMBS: usize, T> UintTryFrom<T> for Uint<BITS, LIMBS>
336where
337 Self: TryFrom<T, Error = ToUintError<Self>>,
338{
339 #[inline]
340 fn uint_try_from(value: T) -> Result<Self, ToUintError<Self>> {
341 Self::try_from(value)
342 }
343}
344
345impl<const BITS: usize, const LIMBS: usize, const BITS_SRC: usize, const LIMBS_SRC: usize>
346 UintTryFrom<Uint<BITS_SRC, LIMBS_SRC>> for Uint<BITS, LIMBS>
347{
348 #[inline]
349 fn uint_try_from(value: Uint<BITS_SRC, LIMBS_SRC>) -> Result<Self, ToUintError<Self>> {
350 let (n, overflow) = Self::overflowing_from_limbs_slice(value.as_limbs());
351 if overflow {
352 Err(ToUintError::ValueTooLarge(BITS, n))
353 } else {
354 Ok(n)
355 }
356 }
357}
358
359pub trait UintTryTo<T>: Sized {
362 #[doc(hidden)]
363 fn uint_try_to(&self) -> Result<T, FromUintError<T>>;
364}
365
366impl<const BITS: usize, const LIMBS: usize, T> UintTryTo<T> for Uint<BITS, LIMBS>
367where
368 T: for<'a> TryFrom<&'a Self, Error = FromUintError<T>>,
369{
370 #[inline]
371 fn uint_try_to(&self) -> Result<T, FromUintError<T>> {
372 T::try_from(self)
373 }
374}
375
376impl<const BITS: usize, const LIMBS: usize, const BITS_DST: usize, const LIMBS_DST: usize>
377 UintTryTo<Uint<BITS_DST, LIMBS_DST>> for Uint<BITS, LIMBS>
378{
379 #[inline]
380 fn uint_try_to(
381 &self,
382 ) -> Result<Uint<BITS_DST, LIMBS_DST>, FromUintError<Uint<BITS_DST, LIMBS_DST>>> {
383 let (n, overflow) = Uint::overflowing_from_limbs_slice(self.as_limbs());
384 if overflow {
385 Err(FromUintError::Overflow(BITS_DST, n, Uint::MAX))
386 } else {
387 Ok(n)
388 }
389 }
390}
391
392impl<const BITS: usize, const LIMBS: usize> TryFrom<u64> for Uint<BITS, LIMBS> {
394 type Error = ToUintError<Self>;
395
396 #[inline]
397 fn try_from(value: u64) -> Result<Self, Self::Error> {
398 if LIMBS <= 1 {
399 if value > Self::MASK {
400 let mut limbs = [0; LIMBS];
402 if LIMBS == 1 {
403 limbs[0] = value & Self::MASK;
404 }
405 return Err(ToUintError::ValueTooLarge(BITS, Self::from_limbs(limbs)));
406 }
407 if LIMBS == 0 {
408 return Ok(Self::ZERO);
409 }
410 }
411 let mut limbs = [0; LIMBS];
412 limbs[0] = value;
413 Ok(Self::from_limbs(limbs))
414 }
415}
416
417impl<const BITS: usize, const LIMBS: usize> TryFrom<u128> for Uint<BITS, LIMBS> {
419 type Error = ToUintError<Self>;
420
421 #[inline]
422 #[allow(clippy::cast_lossless)]
423 #[allow(clippy::cast_possible_truncation)]
424 fn try_from(value: u128) -> Result<Self, Self::Error> {
425 if value <= u64::MAX as u128 {
426 return Self::try_from(value as u64);
427 }
428 if Self::LIMBS < 2 {
429 return Self::try_from(value as u64)
430 .and_then(|n| Err(ToUintError::ValueTooLarge(BITS, n)));
431 }
432 let mut limbs = [0; LIMBS];
433 limbs[0] = value as u64;
434 limbs[1] = (value >> 64) as u64;
435 if Self::LIMBS == 2 && limbs[1] > Self::MASK {
436 limbs[1] %= Self::MASK;
437 Err(ToUintError::ValueTooLarge(BITS, Self::from_limbs(limbs)))
438 } else {
439 Ok(Self::from_limbs(limbs))
440 }
441 }
442}
443
444macro_rules! impl_from_unsigned_int {
446 ($uint:ty) => {
447 impl<const BITS: usize, const LIMBS: usize> TryFrom<$uint> for Uint<BITS, LIMBS> {
448 type Error = ToUintError<Self>;
449
450 #[inline]
451 fn try_from(value: $uint) -> Result<Self, Self::Error> {
452 Self::try_from(value as u64)
453 }
454 }
455 };
456}
457
458impl_from_unsigned_int!(bool);
459impl_from_unsigned_int!(u8);
460impl_from_unsigned_int!(u16);
461impl_from_unsigned_int!(u32);
462impl_from_unsigned_int!(usize);
463
464macro_rules! impl_from_signed_int {
467 ($int:ty, $uint:ty) => {
468 impl<const BITS: usize, const LIMBS: usize> TryFrom<$int> for Uint<BITS, LIMBS> {
469 type Error = ToUintError<Self>;
470
471 #[inline]
472 fn try_from(value: $int) -> Result<Self, Self::Error> {
473 if value.is_negative() {
474 Err(match Self::try_from(value as $uint) {
475 Ok(n) | Err(ToUintError::ValueTooLarge(_, n)) => {
476 ToUintError::ValueNegative(BITS, n)
477 }
478 _ => unreachable!(),
479 })
480 } else {
481 Self::try_from(value as $uint)
482 }
483 }
484 }
485 };
486}
487
488impl_from_signed_int!(i8, u8);
489impl_from_signed_int!(i16, u16);
490impl_from_signed_int!(i32, u32);
491impl_from_signed_int!(i64, u64);
492impl_from_signed_int!(i128, u128);
493impl_from_signed_int!(isize, usize);
494
495#[cfg(feature = "std")]
496impl<const BITS: usize, const LIMBS: usize> TryFrom<f64> for Uint<BITS, LIMBS> {
497 type Error = ToUintError<Self>;
498
499 #[inline]
501 fn try_from(value: f64) -> Result<Self, Self::Error> {
502 if value.is_nan() {
503 return Err(ToUintError::NotANumber(BITS));
504 }
505 if value < 0.0 {
506 let wrapped = match Self::try_from(value.abs()) {
507 Ok(n) | Err(ToUintError::ValueTooLarge(_, n)) => n,
508 _ => Self::ZERO,
509 }
510 .wrapping_neg();
511 return Err(ToUintError::ValueNegative(BITS, wrapped));
512 }
513 #[allow(clippy::cast_precision_loss)] let modulus = (Self::BITS as f64).exp2();
515 if value >= modulus {
516 let wrapped = match Self::try_from(value % modulus) {
517 Ok(n) | Err(ToUintError::ValueTooLarge(_, n)) => n,
518 _ => Self::ZERO,
519 };
520 return Err(ToUintError::ValueTooLarge(BITS, wrapped)); }
522 if value < 0.5 {
523 return Ok(Self::ZERO);
524 }
525 assert!(value.is_normal());
527
528 let value = value + 0.5;
530
531 let bits = value.to_bits();
534 let sign = bits >> 63;
535 assert!(sign == 0);
536 let biased_exponent = (bits >> 52) & 0x7ff;
537 assert!(biased_exponent >= 1023);
538 let exponent = biased_exponent - 1023;
539 let fraction = bits & 0x000f_ffff_ffff_ffff;
540 let mantissa = 0x0010_0000_0000_0000 | fraction;
541
542 #[allow(clippy::cast_possible_truncation)] if exponent as usize > Self::BITS + 52 {
545 return Err(ToUintError::ValueTooLarge(BITS, Self::ZERO));
547 }
548 if exponent <= 52 {
549 Self::try_from(mantissa >> (52 - exponent))
551 } else {
552 #[allow(clippy::cast_possible_truncation)] let exponent = exponent as usize - 52;
554 let n = Self::try_from(mantissa)?;
555 let (n, overflow) = n.overflowing_shl(exponent);
556 if overflow {
557 Err(ToUintError::ValueTooLarge(BITS, n))
558 } else {
559 Ok(n)
560 }
561 }
562 }
563}
564
565#[cfg(feature = "std")]
566impl<const BITS: usize, const LIMBS: usize> TryFrom<f32> for Uint<BITS, LIMBS> {
567 type Error = ToUintError<Self>;
568
569 #[inline]
570 fn try_from(value: f32) -> Result<Self, Self::Error> {
571 #[allow(clippy::cast_lossless)]
572 Self::try_from(value as f64)
573 }
574}
575
576macro_rules! to_value_to_ref {
580 ($t:ty) => {
581 impl<const BITS: usize, const LIMBS: usize> TryFrom<Uint<BITS, LIMBS>> for $t {
582 type Error = FromUintError<Self>;
583
584 #[inline]
585 fn try_from(value: Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
586 Self::try_from(&value)
587 }
588 }
589 };
590}
591
592to_value_to_ref!(bool);
593
594impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for bool {
595 type Error = FromUintError<Self>;
596
597 #[inline]
598 fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
599 if BITS == 0 {
600 return Ok(false);
601 }
602 if value.bit_len() > 1 {
603 return Err(Self::Error::Overflow(BITS, value.bit(0), true));
604 }
605 Ok(value.as_limbs()[0] != 0)
606 }
607}
608
609macro_rules! to_int {
610 ($($int:ty)*) => {$(
611 to_value_to_ref!($int);
612
613 impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for $int {
614 type Error = FromUintError<Self>;
615
616 #[inline]
617 #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
618 fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
619 const SIGNED: bool = <$int>::MIN != 0;
620 const CAPACITY: usize = if SIGNED { <$int>::BITS - 1 } else { <$int>::BITS } as usize;
621 if BITS == 0 {
622 return Ok(0);
623 }
624 if value.bit_len() > CAPACITY {
625 return Err(Self::Error::Overflow(
626 BITS,
627 value.limbs[0] as Self,
628 Self::MAX,
629 ));
630 }
631 Ok(value.as_limbs()[0] as Self)
632 }
633 }
634 )*};
635}
636
637to_int!(i8 u8 i16 u16 i32 u32 i64 u64 isize usize);
638
639to_value_to_ref!(i128);
640
641impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for i128 {
642 type Error = FromUintError<Self>;
643
644 #[inline]
645 #[allow(clippy::cast_lossless)] #[allow(clippy::use_self)] fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
648 if BITS == 0 {
649 return Ok(0);
650 }
651 let mut result = value.limbs[0] as i128;
652 if BITS <= 64 {
653 return Ok(result);
654 }
655 result |= (value.limbs[1] as i128) << 64;
656 if value.bit_len() > 127 {
657 return Err(Self::Error::Overflow(BITS, result, i128::MAX));
658 }
659 Ok(result)
660 }
661}
662
663to_value_to_ref!(u128);
664
665impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for u128 {
666 type Error = FromUintError<Self>;
667
668 #[inline]
669 #[allow(clippy::cast_lossless)] #[allow(clippy::use_self)] fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
672 if BITS == 0 {
673 return Ok(0);
674 }
675 let mut result = value.limbs[0] as u128;
676 if BITS <= 64 {
677 return Ok(result);
678 }
679 result |= (value.limbs[1] as u128) << 64;
680 if value.bit_len() > 128 {
681 return Err(Self::Error::Overflow(BITS, result, u128::MAX));
682 }
683 Ok(result)
684 }
685}
686
687#[cfg(feature = "std")]
690impl<const BITS: usize, const LIMBS: usize> From<Uint<BITS, LIMBS>> for f32 {
691 #[inline]
692 fn from(value: Uint<BITS, LIMBS>) -> Self {
693 Self::from(&value)
694 }
695}
696
697#[cfg(feature = "std")]
698impl<const BITS: usize, const LIMBS: usize> From<&Uint<BITS, LIMBS>> for f32 {
699 #[inline]
703 #[allow(clippy::cast_precision_loss)] fn from(value: &Uint<BITS, LIMBS>) -> Self {
705 let (bits, exponent) = value.most_significant_bits();
706 (bits as Self) * (exponent as Self).exp2()
707 }
708}
709
710#[cfg(feature = "std")]
711impl<const BITS: usize, const LIMBS: usize> From<Uint<BITS, LIMBS>> for f64 {
712 #[inline]
713 fn from(value: Uint<BITS, LIMBS>) -> Self {
714 Self::from(&value)
715 }
716}
717
718#[cfg(feature = "std")]
719impl<const BITS: usize, const LIMBS: usize> From<&Uint<BITS, LIMBS>> for f64 {
720 #[inline]
724 #[allow(clippy::cast_precision_loss)] fn from(value: &Uint<BITS, LIMBS>) -> Self {
726 let (bits, exponent) = value.most_significant_bits();
727 (bits as Self) * (exponent as Self).exp2()
728 }
729}
730
731#[cfg(test)]
732mod test {
733 use super::*;
734 use crate::{const_for, nlimbs};
735
736 #[test]
737 fn test_u64() {
738 assert_eq!(Uint::<0, 0>::try_from(0_u64), Ok(Uint::ZERO));
739 assert_eq!(
740 Uint::<0, 0>::try_from(1_u64),
741 Err(ToUintError::ValueTooLarge(0, Uint::ZERO))
742 );
743 const_for!(BITS in NON_ZERO {
744 const LIMBS: usize = nlimbs(BITS);
745 assert_eq!(Uint::<BITS, LIMBS>::try_from(0_u64), Ok(Uint::ZERO));
746 assert_eq!(Uint::<BITS, LIMBS>::try_from(1_u64).unwrap().as_limbs()[0], 1);
747 });
748 }
749
750 #[test]
751 #[cfg(feature = "std")]
752 fn test_f64() {
753 assert_eq!(Uint::<0, 0>::try_from(0.0_f64), Ok(Uint::ZERO));
754 const_for!(BITS in NON_ZERO {
755 const LIMBS: usize = nlimbs(BITS);
756 assert_eq!(Uint::<BITS, LIMBS>::try_from(0.0_f64), Ok(Uint::ZERO));
757 assert_eq!(Uint::<BITS, LIMBS>::try_from(1.0_f64).unwrap().as_limbs()[0], 1);
758 });
759 assert_eq!(
760 Uint::<7, 1>::try_from(123.499_f64),
761 Ok(Uint::from_limbs([123]))
762 );
763 assert_eq!(
764 Uint::<7, 1>::try_from(123.500_f64),
765 Ok(Uint::from_limbs([124]))
766 );
767 }
768}