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 #[inline]
145 #[must_use]
146 #[track_caller]
147 pub fn from<T>(value: T) -> Self
148 where
149 Self: UintTryFrom<T>,
150 {
151 match Self::uint_try_from(value) {
152 Ok(n) => n,
153 Err(e) => panic!("Uint conversion error: {e}"),
154 }
155 }
156
157 #[inline]
174 #[must_use]
175 pub fn saturating_from<T>(value: T) -> Self
176 where
177 Self: UintTryFrom<T>,
178 {
179 match Self::uint_try_from(value) {
180 Ok(n) => n,
181 Err(ToUintError::ValueTooLarge(..)) => Self::MAX,
182 Err(ToUintError::ValueNegative(..) | ToUintError::NotANumber(_)) => Self::ZERO,
183 }
184 }
185
186 #[inline]
203 #[must_use]
204 pub fn wrapping_from<T>(value: T) -> Self
205 where
206 Self: UintTryFrom<T>,
207 {
208 match Self::uint_try_from(value) {
209 Ok(n) | Err(ToUintError::ValueTooLarge(_, n) | ToUintError::ValueNegative(_, n)) => n,
210 Err(ToUintError::NotANumber(_)) => Self::ZERO,
211 }
212 }
213
214 #[inline]
229 #[must_use]
230 #[track_caller]
231 pub fn to<T>(&self) -> T
232 where
233 Self: UintTryTo<T>,
234 T: Debug,
235 {
236 self.uint_try_to().expect("Uint conversion error")
237 }
238
239 #[inline]
250 #[must_use]
251 pub fn wrapping_to<T>(&self) -> T
252 where
253 Self: UintTryTo<T>,
254 {
255 match self.uint_try_to() {
256 Ok(n) | Err(FromUintError::Overflow(_, n, _)) => n,
257 }
258 }
259
260 #[inline]
271 #[must_use]
272 pub fn saturating_to<T>(&self) -> T
273 where
274 Self: UintTryTo<T>,
275 {
276 match self.uint_try_to() {
277 Ok(n) | Err(FromUintError::Overflow(_, _, n)) => n,
278 }
279 }
280
281 #[inline]
287 #[doc(hidden)]
288 #[must_use]
289 #[track_caller]
290 #[deprecated(since = "1.4.0", note = "Use `::from()` instead.")]
291 pub fn from_uint<const BITS_SRC: usize, const LIMBS_SRC: usize>(
292 value: Uint<BITS_SRC, LIMBS_SRC>,
293 ) -> Self {
294 Self::from_limbs_slice(value.as_limbs())
295 }
296
297 #[inline]
298 #[doc(hidden)]
299 #[must_use]
300 #[deprecated(since = "1.4.0", note = "Use `::checked_from()` instead.")]
301 pub fn checked_from_uint<const BITS_SRC: usize, const LIMBS_SRC: usize>(
302 value: Uint<BITS_SRC, LIMBS_SRC>,
303 ) -> Option<Self> {
304 Self::checked_from_limbs_slice(value.as_limbs())
305 }
306}
307
308#[allow(clippy::module_name_repetitions)]
316pub trait UintTryFrom<T>: Sized {
317 #[doc(hidden)]
318 fn uint_try_from(value: T) -> Result<Self, ToUintError<Self>>;
319}
320
321impl<const BITS: usize, const LIMBS: usize, T> UintTryFrom<T> for Uint<BITS, LIMBS>
323where
324 Self: TryFrom<T, Error = ToUintError<Self>>,
325{
326 #[inline]
327 fn uint_try_from(value: T) -> Result<Self, ToUintError<Self>> {
328 Self::try_from(value)
329 }
330}
331
332impl<const BITS: usize, const LIMBS: usize, const BITS_SRC: usize, const LIMBS_SRC: usize>
333 UintTryFrom<Uint<BITS_SRC, LIMBS_SRC>> for Uint<BITS, LIMBS>
334{
335 #[inline]
336 fn uint_try_from(value: Uint<BITS_SRC, LIMBS_SRC>) -> Result<Self, ToUintError<Self>> {
337 let (n, overflow) = Self::overflowing_from_limbs_slice(value.as_limbs());
338 if overflow {
339 Err(ToUintError::ValueTooLarge(BITS, n))
340 } else {
341 Ok(n)
342 }
343 }
344}
345
346pub trait UintTryTo<T>: Sized {
349 #[doc(hidden)]
350 fn uint_try_to(&self) -> Result<T, FromUintError<T>>;
351}
352
353impl<const BITS: usize, const LIMBS: usize, T> UintTryTo<T> for Uint<BITS, LIMBS>
354where
355 T: for<'a> TryFrom<&'a Self, Error = FromUintError<T>>,
356{
357 #[inline]
358 fn uint_try_to(&self) -> Result<T, FromUintError<T>> {
359 T::try_from(self)
360 }
361}
362
363impl<const BITS: usize, const LIMBS: usize, const BITS_DST: usize, const LIMBS_DST: usize>
364 UintTryTo<Uint<BITS_DST, LIMBS_DST>> for Uint<BITS, LIMBS>
365{
366 #[inline]
367 fn uint_try_to(
368 &self,
369 ) -> Result<Uint<BITS_DST, LIMBS_DST>, FromUintError<Uint<BITS_DST, LIMBS_DST>>> {
370 let (n, overflow) = Uint::overflowing_from_limbs_slice(self.as_limbs());
371 if overflow {
372 Err(FromUintError::Overflow(BITS_DST, n, Uint::MAX))
373 } else {
374 Ok(n)
375 }
376 }
377}
378
379impl<const BITS: usize, const LIMBS: usize> TryFrom<u64> for Uint<BITS, LIMBS> {
381 type Error = ToUintError<Self>;
382
383 #[inline]
384 fn try_from(value: u64) -> Result<Self, Self::Error> {
385 if LIMBS <= 1 {
386 if value > Self::MASK {
387 let mut limbs = [0; LIMBS];
389 if LIMBS == 1 {
390 limbs[0] = value & Self::MASK;
391 }
392 return Err(ToUintError::ValueTooLarge(BITS, Self::from_limbs(limbs)));
393 }
394 if LIMBS == 0 {
395 return Ok(Self::ZERO);
396 }
397 }
398 let mut limbs = [0; LIMBS];
399 limbs[0] = value;
400 Ok(Self::from_limbs(limbs))
401 }
402}
403
404impl<const BITS: usize, const LIMBS: usize> TryFrom<u128> for Uint<BITS, LIMBS> {
406 type Error = ToUintError<Self>;
407
408 #[inline]
409 #[allow(clippy::cast_lossless)]
410 #[allow(clippy::cast_possible_truncation)]
411 fn try_from(value: u128) -> Result<Self, Self::Error> {
412 if value <= u64::MAX as u128 {
413 return Self::try_from(value as u64);
414 }
415 if Self::LIMBS < 2 {
416 return Self::try_from(value as u64)
417 .and_then(|n| Err(ToUintError::ValueTooLarge(BITS, n)));
418 }
419 let mut limbs = [0; LIMBS];
420 limbs[0] = value as u64;
421 limbs[1] = (value >> 64) as u64;
422 if Self::LIMBS == 2 && limbs[1] > Self::MASK {
423 limbs[1] %= Self::MASK;
424 Err(ToUintError::ValueTooLarge(BITS, Self::from_limbs(limbs)))
425 } else {
426 Ok(Self::from_limbs(limbs))
427 }
428 }
429}
430
431macro_rules! impl_from_unsigned_int {
433 ($uint:ty) => {
434 impl<const BITS: usize, const LIMBS: usize> TryFrom<$uint> for Uint<BITS, LIMBS> {
435 type Error = ToUintError<Self>;
436
437 #[inline]
438 fn try_from(value: $uint) -> Result<Self, Self::Error> {
439 Self::try_from(value as u64)
440 }
441 }
442 };
443}
444
445impl_from_unsigned_int!(bool);
446impl_from_unsigned_int!(u8);
447impl_from_unsigned_int!(u16);
448impl_from_unsigned_int!(u32);
449impl_from_unsigned_int!(usize);
450
451macro_rules! impl_from_signed_int {
454 ($int:ty, $uint:ty) => {
455 impl<const BITS: usize, const LIMBS: usize> TryFrom<$int> for Uint<BITS, LIMBS> {
456 type Error = ToUintError<Self>;
457
458 #[inline]
459 fn try_from(value: $int) -> Result<Self, Self::Error> {
460 if value.is_negative() {
461 Err(match Self::try_from(value as $uint) {
462 Ok(n) | Err(ToUintError::ValueTooLarge(_, n)) => {
463 ToUintError::ValueNegative(BITS, n)
464 }
465 _ => unreachable!(),
466 })
467 } else {
468 Self::try_from(value as $uint)
469 }
470 }
471 }
472 };
473}
474
475impl_from_signed_int!(i8, u8);
476impl_from_signed_int!(i16, u16);
477impl_from_signed_int!(i32, u32);
478impl_from_signed_int!(i64, u64);
479impl_from_signed_int!(i128, u128);
480impl_from_signed_int!(isize, usize);
481
482#[cfg(feature = "std")]
483impl<const BITS: usize, const LIMBS: usize> TryFrom<f64> for Uint<BITS, LIMBS> {
484 type Error = ToUintError<Self>;
485
486 #[inline]
488 fn try_from(value: f64) -> Result<Self, Self::Error> {
489 if value.is_nan() {
490 return Err(ToUintError::NotANumber(BITS));
491 }
492 if value < 0.0 {
493 let wrapped = match Self::try_from(value.abs()) {
494 Ok(n) | Err(ToUintError::ValueTooLarge(_, n)) => n,
495 _ => Self::ZERO,
496 }
497 .wrapping_neg();
498 return Err(ToUintError::ValueNegative(BITS, wrapped));
499 }
500 #[allow(clippy::cast_precision_loss)] let modulus = (Self::BITS as f64).exp2();
502 if value >= modulus {
503 let wrapped = match Self::try_from(value % modulus) {
504 Ok(n) | Err(ToUintError::ValueTooLarge(_, n)) => n,
505 _ => Self::ZERO,
506 };
507 return Err(ToUintError::ValueTooLarge(BITS, wrapped)); }
509 if value < 0.5 {
510 return Ok(Self::ZERO);
511 }
512 assert!(value.is_normal());
514
515 let value = value + 0.5;
517
518 let bits = value.to_bits();
521 let sign = bits >> 63;
522 assert!(sign == 0);
523 let biased_exponent = (bits >> 52) & 0x7ff;
524 assert!(biased_exponent >= 1023);
525 let exponent = biased_exponent - 1023;
526 let fraction = bits & 0x000f_ffff_ffff_ffff;
527 let mantissa = 0x0010_0000_0000_0000 | fraction;
528
529 #[allow(clippy::cast_possible_truncation)] if exponent as usize > Self::BITS + 52 {
532 return Err(ToUintError::ValueTooLarge(BITS, Self::ZERO));
534 }
535 if exponent <= 52 {
536 Self::try_from(mantissa >> (52 - exponent))
538 } else {
539 #[allow(clippy::cast_possible_truncation)] let exponent = exponent as usize - 52;
541 let n = Self::try_from(mantissa)?;
542 let (n, overflow) = n.overflowing_shl(exponent);
543 if overflow {
544 Err(ToUintError::ValueTooLarge(BITS, n))
545 } else {
546 Ok(n)
547 }
548 }
549 }
550}
551
552#[cfg(feature = "std")]
553impl<const BITS: usize, const LIMBS: usize> TryFrom<f32> for Uint<BITS, LIMBS> {
554 type Error = ToUintError<Self>;
555
556 #[inline]
557 fn try_from(value: f32) -> Result<Self, Self::Error> {
558 #[allow(clippy::cast_lossless)]
559 Self::try_from(value as f64)
560 }
561}
562
563macro_rules! to_value_to_ref {
567 ($t:ty) => {
568 impl<const BITS: usize, const LIMBS: usize> TryFrom<Uint<BITS, LIMBS>> for $t {
569 type Error = FromUintError<Self>;
570
571 #[inline]
572 fn try_from(value: Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
573 Self::try_from(&value)
574 }
575 }
576 };
577}
578
579to_value_to_ref!(bool);
580
581impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for bool {
582 type Error = FromUintError<Self>;
583
584 #[inline]
585 fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
586 if BITS == 0 {
587 return Ok(false);
588 }
589 if value.bit_len() > 1 {
590 return Err(Self::Error::Overflow(BITS, value.bit(0), true));
591 }
592 Ok(value.as_limbs()[0] != 0)
593 }
594}
595
596macro_rules! to_int {
597 ($($int:ty)*) => {$(
598 to_value_to_ref!($int);
599
600 impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for $int {
601 type Error = FromUintError<Self>;
602
603 #[inline]
604 #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
605 fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
606 const SIGNED: bool = <$int>::MIN != 0;
607 const CAPACITY: usize = if SIGNED { <$int>::BITS - 1 } else { <$int>::BITS } as usize;
608 if BITS == 0 {
609 return Ok(0);
610 }
611 if value.bit_len() > CAPACITY {
612 return Err(Self::Error::Overflow(
613 BITS,
614 value.limbs[0] as Self,
615 Self::MAX,
616 ));
617 }
618 Ok(value.as_limbs()[0] as Self)
619 }
620 }
621 )*};
622}
623
624to_int!(i8 u8 i16 u16 i32 u32 i64 u64 isize usize);
625
626to_value_to_ref!(i128);
627
628impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for i128 {
629 type Error = FromUintError<Self>;
630
631 #[inline]
632 #[allow(clippy::cast_lossless)] #[allow(clippy::use_self)] fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
635 if BITS == 0 {
636 return Ok(0);
637 }
638 let mut result = value.limbs[0] as i128;
639 if BITS <= 64 {
640 return Ok(result);
641 }
642 result |= (value.limbs[1] as i128) << 64;
643 if value.bit_len() > 127 {
644 return Err(Self::Error::Overflow(BITS, result, i128::MAX));
645 }
646 Ok(result)
647 }
648}
649
650to_value_to_ref!(u128);
651
652impl<const BITS: usize, const LIMBS: usize> TryFrom<&Uint<BITS, LIMBS>> for u128 {
653 type Error = FromUintError<Self>;
654
655 #[inline]
656 #[allow(clippy::cast_lossless)] #[allow(clippy::use_self)] fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
659 if BITS == 0 {
660 return Ok(0);
661 }
662 let mut result = value.limbs[0] as u128;
663 if BITS <= 64 {
664 return Ok(result);
665 }
666 result |= (value.limbs[1] as u128) << 64;
667 if value.bit_len() > 128 {
668 return Err(Self::Error::Overflow(BITS, result, u128::MAX));
669 }
670 Ok(result)
671 }
672}
673
674#[cfg(feature = "std")]
677impl<const BITS: usize, const LIMBS: usize> From<Uint<BITS, LIMBS>> for f32 {
678 #[inline]
679 fn from(value: Uint<BITS, LIMBS>) -> Self {
680 Self::from(&value)
681 }
682}
683
684#[cfg(feature = "std")]
685impl<const BITS: usize, const LIMBS: usize> From<&Uint<BITS, LIMBS>> for f32 {
686 #[inline]
690 #[allow(clippy::cast_precision_loss)] fn from(value: &Uint<BITS, LIMBS>) -> Self {
692 let (bits, exponent) = value.most_significant_bits();
693 (bits as Self) * (exponent as Self).exp2()
694 }
695}
696
697#[cfg(feature = "std")]
698impl<const BITS: usize, const LIMBS: usize> From<Uint<BITS, LIMBS>> for f64 {
699 #[inline]
700 fn from(value: Uint<BITS, LIMBS>) -> Self {
701 Self::from(&value)
702 }
703}
704
705#[cfg(feature = "std")]
706impl<const BITS: usize, const LIMBS: usize> From<&Uint<BITS, LIMBS>> for f64 {
707 #[inline]
711 #[allow(clippy::cast_precision_loss)] fn from(value: &Uint<BITS, LIMBS>) -> Self {
713 let (bits, exponent) = value.most_significant_bits();
714 (bits as Self) * (exponent as Self).exp2()
715 }
716}
717
718#[cfg(test)]
719mod test {
720 use super::*;
721 use crate::{const_for, nlimbs};
722
723 #[test]
724 fn test_u64() {
725 assert_eq!(Uint::<0, 0>::try_from(0_u64), Ok(Uint::ZERO));
726 assert_eq!(
727 Uint::<0, 0>::try_from(1_u64),
728 Err(ToUintError::ValueTooLarge(0, Uint::ZERO))
729 );
730 const_for!(BITS in NON_ZERO {
731 const LIMBS: usize = nlimbs(BITS);
732 assert_eq!(Uint::<BITS, LIMBS>::try_from(0_u64), Ok(Uint::ZERO));
733 assert_eq!(Uint::<BITS, LIMBS>::try_from(1_u64).unwrap().as_limbs()[0], 1);
734 });
735 }
736
737 #[test]
738 #[cfg(feature = "std")]
739 fn test_f64() {
740 assert_eq!(Uint::<0, 0>::try_from(0.0_f64), Ok(Uint::ZERO));
741 const_for!(BITS in NON_ZERO {
742 const LIMBS: usize = nlimbs(BITS);
743 assert_eq!(Uint::<BITS, LIMBS>::try_from(0.0_f64), Ok(Uint::ZERO));
744 assert_eq!(Uint::<BITS, LIMBS>::try_from(1.0_f64).unwrap().as_limbs()[0], 1);
745 });
746 assert_eq!(
747 Uint::<7, 1>::try_from(123.499_f64),
748 Ok(Uint::from_limbs([123]))
749 );
750 assert_eq!(
751 Uint::<7, 1>::try_from(123.500_f64),
752 Ok(Uint::from_limbs([124]))
753 );
754 }
755}