Skip to main content

fastnum/decimal/dec/impls/
cast.rs

1use crate::{
2    bint,
3    bint::UInt,
4    decimal::{Decimal, ParseError, Sign, UnsignedDecimal},
5    utils::const_generics::{Dimension, Narrow, Widen},
6    Cast, TryCast,
7};
8
9type D<const N: usize> = Decimal<N>;
10type UD<const N: usize> = UnsignedDecimal<N>;
11
12impl<const N: usize, const M: usize> Cast<D<N>> for D<M>
13where
14    Dimension<N, M>: Widen,
15{
16    #[inline(always)]
17    fn cast(self) -> D<N> {
18        D::new(self.digits.cast(), self.cb)
19    }
20}
21
22impl<const N: usize, const M: usize> TryCast<D<N>> for D<M>
23where
24    Dimension<N, M>: Narrow,
25{
26    type Error = ParseError;
27
28    #[inline(always)]
29    fn try_cast(self) -> Result<D<N>, Self::Error> {
30        <UInt<M> as TryCast<UInt<N>>>::try_cast(self.digits)
31            .map(|digits| D::new(digits, self.cb))
32            .map_err(|e| map_error(e, self.sign()))
33    }
34}
35
36impl<const N: usize, const M: usize> TryCast<UD<N>> for D<M> {
37    type Error = ParseError;
38
39    #[inline(always)]
40    fn try_cast(self) -> Result<UD<N>, Self::Error> {
41        if self.is_negative() {
42            Err(ParseError::Signed)
43        } else {
44            debug_assert!(self.is_positive());
45
46            if N >= M || self.digits().bits() <= UInt::<N>::BITS {
47                // SAFETY:
48                // - N >= M, so it's safe to transmute.
49                // - N < M, but higher bits are zero, so it's safe to transmute.
50                #[allow(unsafe_code)]
51                {
52                    let d = unsafe { self._transmute() };
53                    Ok(UD::new(d))
54                }
55            } else {
56                Err(map_overflow(self.sign()))
57            }
58        }
59    }
60}
61
62#[inline(always)]
63fn map_overflow(sign: Sign) -> ParseError {
64    match sign {
65        Sign::Plus => ParseError::PosOverflow,
66        Sign::Minus => ParseError::NegOverflow,
67    }
68}
69
70#[inline(always)]
71fn map_error(e: bint::ParseError, sign: Sign) -> ParseError {
72    match e {
73        bint::ParseError::Empty => ParseError::Empty,
74        bint::ParseError::InvalidDigit => ParseError::InvalidLiteral,
75        bint::ParseError::PosOverflow => map_overflow(sign),
76        bint::ParseError::NegOverflow => ParseError::NegOverflow,
77        bint::ParseError::Zero => ParseError::Unknown,
78        bint::ParseError::Signed => ParseError::Signed,
79        bint::ParseError::InvalidRadix => ParseError::InvalidRadix,
80        bint::ParseError::Unknown => ParseError::Unknown,
81    }
82}