ruint/
from.rs

1// FEATURE: (BLOCKED) It would be nice to impl From<_> as well, but then the
2// generic implementation `impl<T: Into<U>, U> TryFrom<U> for T` conflicts with
3// our own implementation. This means we can only implement one.
4// In principle this can be worked around by `specialization`, but that
5// triggers other compiler issues at the moment.
6
7// impl<T, const BITS: usize> From<T> for Uint<BITS>
8// where
9//     [(); nlimbs(BITS)]:,
10//     Uint<BITS>: TryFrom<T>,
11// {
12//     fn from(t: T) -> Self {
13//         Self::try_from(t).unwrap()
14//     }
15// }
16// See <https://github.com/rust-lang/rust/issues/50133>
17
18// FEATURE: (BLOCKED) It would be nice if we could make TryFrom assignment work
19// for all Uints.
20// impl<
21//         const BITS_SRC: usize,
22//         const LIMBS_SRC: usize,
23//         const BITS_DST: usize,
24//         const LIMBS_DST: usize,
25//     > TryFrom<Uint<BITS_SRC, LIMBS_SRC>> for Uint<BITS_DST, LIMBS_DST>
26// {
27//     type Error = ToUintError;
28
29//     fn try_from(value: Uint<BITS_SRC, LIMBS_SRC>) -> Result<Self,
30// Self::Error> {
31//     }
32// }
33
34use crate::Uint;
35use core::{fmt, fmt::Debug};
36
37/// Error for [`TryFrom<T>`][TryFrom] for [`Uint`].
38#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
39pub enum ToUintError<T> {
40    /// Value is too large to fit the Uint.
41    ///
42    /// `.0` is `BITS` and `.1` is the wrapped value.
43    ValueTooLarge(usize, T),
44
45    /// Negative values can not be represented as Uint.
46    ///
47    /// `.0` is `BITS` and `.1` is the wrapped value.
48    ValueNegative(usize, T),
49
50    /// 'Not a number' (NaN) can not be represented as Uint
51    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/// Error for [`TryFrom<Uint>`][TryFrom].
76#[allow(clippy::derive_partial_eq_without_eq)] // False positive
77#[allow(clippy::module_name_repetitions)]
78#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
79pub enum FromUintError<T> {
80    /// The Uint value is too large for the target type.
81    ///
82    /// `.0` number of `BITS` in the Uint, `.1` is the wrapped value and
83    /// `.2` is the maximum representable value in the target type.
84    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/// Error for [`TryFrom<Uint>`][TryFrom] for [`ark_ff`](https://docs.rs/ark-ff) and others.
104#[allow(dead_code)] // This is used by some support features.
105#[derive(Debug, Clone, Copy)]
106pub enum ToFieldError {
107    /// Number is equal or larger than the target field modulus.
108    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    /// Constructs a new [`Uint`] from a u64.
127    ///
128    /// Saturates at the maximum value of the [`Uint`] if the value is too
129    /// large.
130    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    /// Construct a new [`Uint`] from the value.
140    ///
141    /// # Panics
142    ///
143    /// Panics if the conversion fails, for example if the value is too large
144    /// for the bit-size of the [`Uint`]. The panic will be attributed to the
145    /// call site.
146    ///
147    /// # Examples
148    ///
149    /// ```
150    /// # use ruint::{Uint, uint, aliases::*};
151    /// # uint!{
152    /// assert_eq!(U8::from(142_u16), 142_U8);
153    /// assert_eq!(U64::from(0x7014b4c2d1f2_U256), 0x7014b4c2d1f2_U64);
154    /// assert_eq!(U64::from(3.145), 3_U64);
155    /// # }
156    /// ```
157    #[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    /// Construct a new [`Uint`] from the value saturating the value to the
171    /// minimum or maximum value of the [`Uint`].
172    ///
173    /// If the value is not a number (like `f64::NAN`), then the result is
174    /// set zero.
175    ///
176    /// # Examples
177    ///
178    /// ```
179    /// # use ruint::{Uint, uint, aliases::*};
180    /// # uint!{
181    /// assert_eq!(U8::saturating_from(300_u16), 255_U8);
182    /// assert_eq!(U8::saturating_from(-10_i16), 0_U8);
183    /// assert_eq!(U32::saturating_from(0x7014b4c2d1f2_U256), U32::MAX);
184    /// # }
185    /// ```
186    #[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    /// Construct a new [`Uint`] from the value saturating the value to the
200    /// minimum or maximum value of the [`Uint`].
201    ///
202    /// If the value is not a number (like `f64::NAN`), then the result is
203    /// set zero.
204    ///
205    /// # Examples
206    ///
207    /// ```
208    /// # use ruint::{Uint, uint, aliases::*};
209    /// # uint!{
210    /// assert_eq!(U8::wrapping_from(300_u16), 44_U8);
211    /// assert_eq!(U8::wrapping_from(-10_i16), 246_U8);
212    /// assert_eq!(U32::wrapping_from(0x7014b4c2d1f2_U256), 0xb4c2d1f2_U32);
213    /// # }
214    /// ```
215    #[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    /// # Panics
228    ///
229    /// Panics if the conversion fails, for example if the value is too large
230    /// for the bit-size of the target type.
231    ///
232    /// # Examples
233    ///
234    /// ```
235    /// # use ruint::{Uint, uint, aliases::*};
236    /// # uint!{
237    /// assert_eq!(300_U12.to::<i16>(), 300_i16);
238    /// assert_eq!(300_U12.to::<U256>(), 300_U256);
239    /// # }
240    /// ```
241    #[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    /// # Examples
253    ///
254    /// ```
255    /// # use ruint::{Uint, uint, aliases::*};
256    /// # uint!{
257    /// assert_eq!(300_U12.wrapping_to::<i8>(), 44_i8);
258    /// assert_eq!(255_U32.wrapping_to::<i8>(), -1_i8);
259    /// assert_eq!(0x1337cafec0d3_U256.wrapping_to::<U32>(), 0xcafec0d3_U32);
260    /// # }
261    /// ```
262    #[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    /// # Examples
274    ///
275    /// ```
276    /// # use ruint::{Uint, uint, aliases::*};
277    /// # uint!{
278    /// assert_eq!(300_U12.saturating_to::<i16>(), 300_i16);
279    /// assert_eq!(255_U32.saturating_to::<i8>(), 127);
280    /// assert_eq!(0x1337cafec0d3_U256.saturating_to::<U32>(), U32::MAX);
281    /// # }
282    /// ```
283    #[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    /// Construct a new [`Uint`] from a potentially different sized [`Uint`].
295    ///
296    /// # Panics
297    ///
298    /// Panics if the value is too large for the target type.
299    #[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/// ⚠️ Workaround for [Rust issue #50133](https://github.com/rust-lang/rust/issues/50133).
322/// Use [`TryFrom`] instead.
323///
324/// We cannot implement [`TryFrom<Uint>`] for [`Uint`] directly, but we can
325/// create a new identical trait and implement it there. We can even give this
326/// trait a blanket implementation inheriting all [`TryFrom<_>`]
327/// implementations.
328#[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
334/// Blanket implementation for any type that implements [`TryFrom<Uint>`].
335impl<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
359/// ⚠️ Workaround for [Rust issue #50133](https://github.com/rust-lang/rust/issues/50133).
360/// Use [`TryFrom`] instead.
361pub 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
392// u64 is a single limb, so this is the base case
393impl<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                // Construct wrapped value
401                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
417// u128 version is handled specially in because it covers two limbs.
418impl<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
444// Unsigned int version upcast to u64
445macro_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
464// Signed int version check for positive and delegate to the corresponding
465// `uint`.
466macro_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    // TODO: Correctly implement wrapping.
500    #[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)] // BITS is small-ish
514        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)); // Wrapping
521        }
522        if value < 0.5 {
523            return Ok(Self::ZERO);
524        }
525        // All non-normal cases should have been handled above
526        assert!(value.is_normal());
527
528        // Add offset to round to nearest integer.
529        let value = value + 0.5;
530
531        // Parse IEEE-754 double
532        // Sign should be zero, exponent should be >= 0.
533        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        // Convert mantissa * 2^(exponent - 52) to Uint
543        #[allow(clippy::cast_possible_truncation)] // exponent is small-ish
544        if exponent as usize > Self::BITS + 52 {
545            // Wrapped value is zero because the value is extended with zero bits.
546            return Err(ToUintError::ValueTooLarge(BITS, Self::ZERO));
547        }
548        if exponent <= 52 {
549            // Truncate mantissa
550            Self::try_from(mantissa >> (52 - exponent))
551        } else {
552            #[allow(clippy::cast_possible_truncation)] // exponent is small-ish
553            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
576// Convert Uint to integer types
577
578// Required because a generic rule violates the orphan rule
579macro_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)] // Safe casts
646    #[allow(clippy::use_self)] // More readable
647    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)] // Safe casts
670    #[allow(clippy::use_self)] // More readable
671    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// Convert Uint to floating point
688
689#[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    /// Approximate single precision float.
700    ///
701    /// Returns `f32::INFINITY` if the value is too large to represent.
702    #[inline]
703    #[allow(clippy::cast_precision_loss)] // Documented
704    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    /// Approximate double precision float.
721    ///
722    /// Returns `f64::INFINITY` if the value is too large to represent.
723    #[inline]
724    #[allow(clippy::cast_precision_loss)] // Documented
725    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}