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    /// Construct a new [`Uint`] from the value.
127    ///
128    /// # Panics
129    ///
130    /// Panics if the conversion fails, for example if the value is too large
131    /// for the bit-size of the [`Uint`]. The panic will be attributed to the
132    /// call site.
133    ///
134    /// # Examples
135    ///
136    /// ```
137    /// # use ruint::{Uint, uint, aliases::*};
138    /// # uint!{
139    /// assert_eq!(U8::from(142_u16), 142_U8);
140    /// assert_eq!(U64::from(0x7014b4c2d1f2_U256), 0x7014b4c2d1f2_U64);
141    /// assert_eq!(U64::from(3.145), 3_U64);
142    /// # }
143    /// ```
144    #[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    /// Construct a new [`Uint`] from the value saturating the value to the
158    /// minimum or maximum value of the [`Uint`].
159    ///
160    /// If the value is not a number (like `f64::NAN`), then the result is
161    /// set zero.
162    ///
163    /// # Examples
164    ///
165    /// ```
166    /// # use ruint::{Uint, uint, aliases::*};
167    /// # uint!{
168    /// assert_eq!(U8::saturating_from(300_u16), 255_U8);
169    /// assert_eq!(U8::saturating_from(-10_i16), 0_U8);
170    /// assert_eq!(U32::saturating_from(0x7014b4c2d1f2_U256), U32::MAX);
171    /// # }
172    /// ```
173    #[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    /// Construct a new [`Uint`] from the value saturating the value to the
187    /// minimum or maximum value of the [`Uint`].
188    ///
189    /// If the value is not a number (like `f64::NAN`), then the result is
190    /// set zero.
191    ///
192    /// # Examples
193    ///
194    /// ```
195    /// # use ruint::{Uint, uint, aliases::*};
196    /// # uint!{
197    /// assert_eq!(U8::wrapping_from(300_u16), 44_U8);
198    /// assert_eq!(U8::wrapping_from(-10_i16), 246_U8);
199    /// assert_eq!(U32::wrapping_from(0x7014b4c2d1f2_U256), 0xb4c2d1f2_U32);
200    /// # }
201    /// ```
202    #[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    /// # Panics
215    ///
216    /// Panics if the conversion fails, for example if the value is too large
217    /// for the bit-size of the target type.
218    ///
219    /// # Examples
220    ///
221    /// ```
222    /// # use ruint::{Uint, uint, aliases::*};
223    /// # uint!{
224    /// assert_eq!(300_U12.to::<i16>(), 300_i16);
225    /// assert_eq!(300_U12.to::<U256>(), 300_U256);
226    /// # }
227    /// ```
228    #[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    /// # Examples
240    ///
241    /// ```
242    /// # use ruint::{Uint, uint, aliases::*};
243    /// # uint!{
244    /// assert_eq!(300_U12.wrapping_to::<i8>(), 44_i8);
245    /// assert_eq!(255_U32.wrapping_to::<i8>(), -1_i8);
246    /// assert_eq!(0x1337cafec0d3_U256.wrapping_to::<U32>(), 0xcafec0d3_U32);
247    /// # }
248    /// ```
249    #[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    /// # Examples
261    ///
262    /// ```
263    /// # use ruint::{Uint, uint, aliases::*};
264    /// # uint!{
265    /// assert_eq!(300_U12.saturating_to::<i16>(), 300_i16);
266    /// assert_eq!(255_U32.saturating_to::<i8>(), 127);
267    /// assert_eq!(0x1337cafec0d3_U256.saturating_to::<U32>(), U32::MAX);
268    /// # }
269    /// ```
270    #[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    /// Construct a new [`Uint`] from a potentially different sized [`Uint`].
282    ///
283    /// # Panics
284    ///
285    /// Panics if the value is too large for the target type.
286    #[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/// ⚠️ Workaround for [Rust issue #50133](https://github.com/rust-lang/rust/issues/50133).
309/// Use [`TryFrom`] instead.
310///
311/// We cannot implement [`TryFrom<Uint>`] for [`Uint`] directly, but we can
312/// create a new identical trait and implement it there. We can even give this
313/// trait a blanket implementation inheriting all [`TryFrom<_>`]
314/// implementations.
315#[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
321/// Blanket implementation for any type that implements [`TryFrom<Uint>`].
322impl<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
346/// ⚠️ Workaround for [Rust issue #50133](https://github.com/rust-lang/rust/issues/50133).
347/// Use [`TryFrom`] instead.
348pub 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
379// u64 is a single limb, so this is the base case
380impl<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                // Construct wrapped value
388                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
404// u128 version is handled specially in because it covers two limbs.
405impl<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
431// Unsigned int version upcast to u64
432macro_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
451// Signed int version check for positive and delegate to the corresponding
452// `uint`.
453macro_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    // TODO: Correctly implement wrapping.
487    #[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)] // BITS is small-ish
501        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)); // Wrapping
508        }
509        if value < 0.5 {
510            return Ok(Self::ZERO);
511        }
512        // All non-normal cases should have been handled above
513        assert!(value.is_normal());
514
515        // Add offset to round to nearest integer.
516        let value = value + 0.5;
517
518        // Parse IEEE-754 double
519        // Sign should be zero, exponent should be >= 0.
520        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        // Convert mantissa * 2^(exponent - 52) to Uint
530        #[allow(clippy::cast_possible_truncation)] // exponent is small-ish
531        if exponent as usize > Self::BITS + 52 {
532            // Wrapped value is zero because the value is extended with zero bits.
533            return Err(ToUintError::ValueTooLarge(BITS, Self::ZERO));
534        }
535        if exponent <= 52 {
536            // Truncate mantissa
537            Self::try_from(mantissa >> (52 - exponent))
538        } else {
539            #[allow(clippy::cast_possible_truncation)] // exponent is small-ish
540            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
563// Convert Uint to integer types
564
565// Required because a generic rule violates the orphan rule
566macro_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)] // Safe casts
633    #[allow(clippy::use_self)] // More readable
634    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)] // Safe casts
657    #[allow(clippy::use_self)] // More readable
658    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// Convert Uint to floating point
675
676#[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    /// Approximate single precision float.
687    ///
688    /// Returns `f32::INFINITY` if the value is too large to represent.
689    #[inline]
690    #[allow(clippy::cast_precision_loss)] // Documented
691    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    /// Approximate double precision float.
708    ///
709    /// Returns `f64::INFINITY` if the value is too large to represent.
710    #[inline]
711    #[allow(clippy::cast_precision_loss)] // Documented
712    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}