Skip to main content

primitive_fixed_point_decimal/
const_scale_fpdec.rs

1use crate::fpdec_inner::FpdecInner;
2use crate::oob_scale_fpdec::OobScaleFpdec;
3use crate::{IntoRatioInt, ParseError, Rounding};
4
5use core::{fmt, num::ParseIntError, ops, str::FromStr};
6
7#[allow(unused_imports)]
8use num_traits::float::FloatCore; // used only for `no_std`
9use num_traits::{cast::FromPrimitive, Num, Signed};
10
11/// Const-scale fixed-point decimal.
12///
13/// `I` is the inner integer type. It could be signed `i8`, `i16`, `i32`,
14/// `i64`, `i128`, or unsigned `u8`, `u16`, `u32`, `u64`, `u128`, with
15/// about 2, 4, 9, 18/19 and 38 significant digits respectively.
16///
17/// `S` is the static scale. Positive means fraction precision. Negative
18/// means omitting the low-order digits of integer values.
19///
20/// For example, `ConstScaleFpdec<i64, 4>` means using `i64` as the underlying
21/// integer, and having `4` fraction precision.
22///
23/// See [the module-level documentation](super) for more information.
24#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default)]
25#[repr(transparent)]
26pub struct ConstScaleFpdec<I, const S: i32>(I);
27
28impl<I, const S: i32> ConstScaleFpdec<I, S>
29where
30    I: FpdecInner,
31{
32    crate::none_scale_common::define_none_scale_common!();
33
34    /// The static scale.
35    pub const SCALE: i32 = S;
36
37    /// Checked multiplication.
38    ///
39    /// Equivalent to [`Self::checked_mul_ext`] with `Rounding::Round`.
40    ///
41    /// If you make sure no overflow error, and the result type has the same
42    /// scale (`SR`=`S`), you can use `*` and `*=` instead for convenience.
43    #[must_use]
44    pub fn checked_mul<J, const S2: i32, const SR: i32>(
45        self,
46        rhs: ConstScaleFpdec<J, S2>,
47    ) -> Option<ConstScaleFpdec<I, SR>>
48    where
49        J: FpdecInner,
50    {
51        self.checked_mul_ext(rhs, Rounding::Round)
52    }
53
54    /// Checked multiplication. Computes `self * rhs`, returning `None` if
55    /// overflow occurred or the scale difference `S + S2 - SR` is out of range
56    /// `[-Self::DIGITS, Self::DIGITS]`.
57    ///
58    /// The type of `rhs` can have different inner integer `J` and scale `S2`
59    /// with `self`. The type of result must have the same inner integer `I`
60    /// while have different scale `SR`.
61    ///
62    /// If the scale of the result's type `SR` is less than the sum of
63    /// scales of the two multiplicands `S + S2`, then rounding operations
64    /// are required and precision may be lost.
65    /// You can specify the rounding type.
66    ///
67    /// # Examples
68    ///
69    /// ```
70    /// use primitive_fixed_point_decimal::{ConstScaleFpdec, Rounding, fpdec};
71    /// type Balance = ConstScaleFpdec<i64, 2>;
72    /// type FeeRate = ConstScaleFpdec<i16, 4>; // different types
73    ///
74    /// let balance: Balance = fpdec!(12.30);
75    /// let rate: FeeRate = fpdec!(0.01);
76    ///
77    /// let fee: Balance = balance.checked_mul(rate).unwrap();
78    /// assert_eq!(fee, fpdec!(0.12));
79    ///
80    /// let fee: Balance = balance.checked_mul_ext(rate, Rounding::Ceiling).unwrap();
81    /// assert_eq!(fee, fpdec!(0.13));
82    /// ```
83    #[must_use]
84    pub fn checked_mul_ext<J, const S2: i32, const SR: i32>(
85        self,
86        rhs: ConstScaleFpdec<J, S2>,
87        rounding: Rounding,
88    ) -> Option<ConstScaleFpdec<I, SR>>
89    where
90        J: FpdecInner,
91    {
92        self.0
93            .checked_mul_ext(I::from(rhs.0)?, S + S2 - SR, rounding)
94            .map(ConstScaleFpdec)
95    }
96
97    /// Checked division.
98    ///
99    /// Equivalent to [`Self::checked_div_ext`] with `Rounding::Round`.
100    ///
101    /// If you make sure no overflow or 0-division error, and the result type
102    /// has the same scale (`SR`=`S`), you can use `/` and `/=` instead for
103    /// convenience.
104    #[must_use]
105    pub fn checked_div<J, const S2: i32, const SR: i32>(
106        self,
107        rhs: ConstScaleFpdec<J, S2>,
108    ) -> Option<ConstScaleFpdec<I, SR>>
109    where
110        J: FpdecInner,
111    {
112        self.checked_div_ext(rhs, Rounding::Round)
113    }
114
115    /// Checked division. Computes `self / rhs`, returning `None` if
116    /// division by 0, or overflow occurred, or the scale difference
117    /// `S - S2 - SR` is out of range `[-Self::DIGITS, Self::DIGITS]`.
118    ///
119    /// The type of `rhs` can have different inner integer `J` and scale `S2`
120    /// with `self`. The type of result must have the same inner integer `I`
121    /// while have different scale `SR`.
122    ///
123    /// You can specify the rounding type.
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// use primitive_fixed_point_decimal::{ConstScaleFpdec, Rounding, fpdec};
129    /// type Balance = ConstScaleFpdec<i64, 2>;
130    /// type FeeRate = ConstScaleFpdec<i16, 4>; // different types
131    ///
132    /// let rate: FeeRate = fpdec!(0.03);
133    /// let fee: Balance = fpdec!(0.13);
134    ///
135    /// let balance: Balance = fee.checked_div_ext(rate, Rounding::Ceiling).unwrap();
136    /// assert_eq!(balance, fpdec!(4.34));
137    /// ```
138    #[must_use]
139    pub fn checked_div_ext<J, const S2: i32, const SR: i32>(
140        self,
141        rhs: ConstScaleFpdec<J, S2>,
142        rounding: Rounding,
143    ) -> Option<ConstScaleFpdec<I, SR>>
144    where
145        J: FpdecInner,
146    {
147        self.0
148            .checked_div_ext(I::from(rhs.0)?, S - S2 - SR, rounding)
149            .map(ConstScaleFpdec)
150    }
151
152    /// Round the decimal at the specified scale.
153    ///
154    /// Equivalent to [`Self::round_ext`] with `Rounding::Round`.
155    #[must_use]
156    pub fn round(self, scale: i32) -> Self {
157        self.round_ext(scale, Rounding::Round)
158    }
159
160    /// Round the decimal at the specified scale with rounding type.
161    ///
162    /// Return the original decimal if `scale >= S`.
163    ///
164    /// Examples:
165    ///
166    /// ```
167    /// use primitive_fixed_point_decimal::{ConstScaleFpdec, Rounding, fpdec};
168    /// type Price = ConstScaleFpdec<i64, 8>;
169    ///
170    /// let price: Price = fpdec!(12.12345678);
171    ///
172    /// assert_eq!(price.round(6), fpdec!(12.123457)); // `Rounding::Round` as default
173    ///
174    /// assert_eq!(price.round_ext(6, Rounding::Floor), fpdec!(12.123456));
175    /// ```
176    #[must_use]
177    pub fn round_ext(self, scale: i32, rounding: Rounding) -> Self {
178        Self(self.0.round_diff_with_rounding(S - scale, rounding))
179    }
180}
181
182impl<I, const S: i32> ConstScaleFpdec<I, S>
183where
184    I: FpdecInner + Signed,
185{
186    crate::none_scale_common::define_none_scale_common_signed!();
187}
188
189impl<I, const S: i32> fmt::Debug for ConstScaleFpdec<I, S>
190where
191    I: fmt::Display,
192{
193    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
194        write!(f, "Fpdec({},{})", self.0, S)
195    }
196}
197
198/// Display the decimal.
199///
200/// It supports some [formatting options](https://doc.rust-lang.org/std/fmt/index.html#formatting-parameters):
201/// width, fill, alignment, precision, sign and 0-fill.
202///
203/// **Panic**: if the scale `S` is too big (>200 or <-200) or the specified
204/// precision is too big (>200).
205///
206/// Examples:
207///
208/// ```
209/// use primitive_fixed_point_decimal::{ConstScaleFpdec, fpdec};
210/// type Decimal = ConstScaleFpdec<i32, 4>;
211///
212/// let d: Decimal = fpdec!(12.3470);
213///
214/// assert_eq!(format!("{}", d), "12.347"); // no option set: omit tailing 0
215/// assert_eq!(format!("{:.4}", d), "12.3470"); // set precision: pad 0
216/// assert_eq!(format!("{:.2}", d), "12.35"); // set smaller precision: round the number
217/// assert_eq!(format!("{:x>10}", d), "xxxx12.347"); // set width, fill, alignment
218/// assert_eq!(format!("{:+}", d), "+12.347"); // set sign
219impl<I, const S: i32> fmt::Display for ConstScaleFpdec<I, S>
220where
221    I: FpdecInner + fmt::Display,
222{
223    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
224        self.0.display_fmt(S, f)
225    }
226}
227
228/// Read decimal from string.
229///
230/// This method has 2 limitations:
231/// 1. Support decimal format only but not scientific notation;
232/// 2. Return `ParseError::Precision` if the string has more precision than `S`.
233///
234/// If you want to skip these limitations, you can parse the string
235/// to float number first and then convert the number to this decimal.
236///
237/// Examples:
238///
239/// ```
240/// use core::str::FromStr;
241/// use primitive_fixed_point_decimal::{ConstScaleFpdec, ParseError};
242/// type Decimal = ConstScaleFpdec<i16, 4>;
243///
244/// assert_eq!(Decimal::from_str("1.23"), Decimal::try_from(1.23));
245/// assert_eq!(Decimal::from_str("9999"), Err(ParseError::Overflow));
246/// assert_eq!(Decimal::from_str("1.23456"), Err(ParseError::Precision));
247/// ```
248impl<I, const S: i32> FromStr for ConstScaleFpdec<I, S>
249where
250    I: FpdecInner + Num<FromStrRadixErr = ParseIntError>,
251{
252    type Err = ParseError;
253    fn from_str(s: &str) -> Result<Self, ParseError> {
254        I::try_from_str(s, S).map(Self)
255    }
256}
257
258impl<I, const S: i32> From<OobScaleFpdec<I>> for ConstScaleFpdec<I, S>
259where
260    I: FpdecInner,
261{
262    /// Convert from `OobScaleFpdec` with scale `S` to `ConstScaleFpdec`.
263    ///
264    /// Examples:
265    ///
266    /// ```
267    /// use primitive_fixed_point_decimal::{ConstScaleFpdec, OobScaleFpdec, fpdec};
268    /// type ConstDec = ConstScaleFpdec<i32, 6>;
269    /// type OobDec = OobScaleFpdec<i32>; // the OOB scale is 6 too
270    ///
271    /// let od: OobDec = fpdec!(123.45, 6); // make sure that `od` has the same scale=6
272    /// let sd: ConstDec = od.into();
273    /// assert_eq!(sd, fpdec!(123.45));
274    /// ```
275    fn from(od: OobScaleFpdec<I>) -> Self {
276        Self(od.mantissa())
277    }
278}
279
280macro_rules! convert_from_int {
281    ($from_int_type:ty) => {
282        impl<I, const S: i32> TryFrom<$from_int_type> for ConstScaleFpdec<I, S>
283        where
284            I: FpdecInner,
285        {
286            type Error = ParseError;
287
288            /// Convert from integer. Returning error if overflow occurred
289            /// or lossing precision under `scale < 0`.
290            ///
291            /// Examples:
292            ///
293            /// ```
294            /// use core::str::FromStr;
295            /// use primitive_fixed_point_decimal::{ConstScaleFpdec, ParseError};
296            /// type Decimal = ConstScaleFpdec<i32, 6>;
297            /// type NegPrec = ConstScaleFpdec<i16, -6>;
298            ///
299            /// assert_eq!(Decimal::try_from(123).unwrap(), Decimal::from_str("123").unwrap());
300            /// assert_eq!(Decimal::try_from(123_i8).unwrap(), Decimal::from_str("123").unwrap());
301            /// assert_eq!(NegPrec::try_from(12000000).unwrap(), NegPrec::from_str("12000000").unwrap());
302            /// assert_eq!(Decimal::try_from(9999999), Err(ParseError::Overflow));
303            /// assert_eq!(NegPrec::try_from(123), Err(ParseError::Precision));
304            /// ```
305            fn try_from(i: $from_int_type) -> Result<Self, Self::Error> {
306                if S > 0 {
307                    // convert from type i to I first
308                    let i2 = I::from(i).ok_or(ParseError::Overflow)?;
309                    I::checked_from_int(i2, S).map(Self)
310                } else {
311                    // convert to fpdec inner first
312                    let i2 = i.checked_from_int(S)?;
313                    I::from(i2).ok_or(ParseError::Overflow).map(Self)
314                }
315            }
316        }
317    };
318}
319convert_from_int!(i8);
320convert_from_int!(i16);
321convert_from_int!(i32);
322convert_from_int!(i64);
323convert_from_int!(i128);
324convert_from_int!(u8);
325convert_from_int!(u16);
326convert_from_int!(u32);
327convert_from_int!(u64);
328convert_from_int!(u128);
329
330macro_rules! convert_from_float {
331    ($float_type:ty, $from_fn:ident, $to_fn:ident) => {
332        impl<I, const S: i32> TryFrom<$float_type> for ConstScaleFpdec<I, S>
333        where
334            I: FromPrimitive + FpdecInner,
335        {
336            type Error = ParseError;
337
338            /// Convert from float type. Returning error if overflow occurred.
339            ///
340            /// Since it's hard for the float types to represent decimal fraction
341            /// exactly, so this method always rounds the float number into
342            /// ConstScaleFpdec.
343            ///
344            /// Examples:
345            ///
346            /// ```
347            /// use core::str::FromStr;
348            /// use primitive_fixed_point_decimal::{ConstScaleFpdec, ParseError};
349            /// type Decimal = ConstScaleFpdec<i32, 4>;
350            ///
351            /// assert_eq!(Decimal::try_from(1.23).unwrap(), Decimal::from_str("1.23").unwrap());
352            /// assert_eq!(Decimal::try_from(1.23456789).unwrap(), Decimal::from_str("1.2346").unwrap());
353            /// ```
354            fn try_from(f: $float_type) -> Result<Self, Self::Error> {
355                let inner_f = if S > 0 {
356                    f * 10.0.powi(S)
357                } else if S < 0 {
358                    f / 10.0.powi(-S)
359                } else {
360                    f
361                };
362                I::$from_fn(inner_f.round())
363                    .map(Self)
364                    .ok_or(ParseError::Overflow)
365            }
366        }
367
368        impl<I, const S: i32> From<ConstScaleFpdec<I, S>> for $float_type
369        where
370            I: FpdecInner,
371        {
372            /// Convert into float type.
373            ///
374            /// Examples:
375            ///
376            /// ```
377            /// use core::str::FromStr;
378            /// use primitive_fixed_point_decimal::{ConstScaleFpdec, ParseError, fpdec};
379            /// type Decimal = ConstScaleFpdec<i32, 4>;
380            ///
381            /// let dec: Decimal = fpdec!(1.23);
382            /// let f: f32 = dec.into();
383            /// assert_eq!(f, 1.23);
384            ///
385            /// type Decimal2 = ConstScaleFpdec<i32, -3>;
386            /// let dec: Decimal2 = fpdec!(123000);
387            /// let f: f32 = dec.into();
388            /// assert_eq!(f, 123000.0);
389            /// ```
390            fn from(dec: ConstScaleFpdec<I, S>) -> Self {
391                let f = dec.0.$to_fn().unwrap();
392                if S > 0 {
393                    f / 10.0.powi(S)
394                } else if S < 0 {
395                    f * 10.0.powi(-S)
396                } else {
397                    f
398                }
399            }
400        }
401    };
402}
403
404convert_from_float!(f32, from_f32, to_f32);
405convert_from_float!(f64, from_f64, to_f64);
406
407impl<I, const S: i32> ops::Neg for ConstScaleFpdec<I, S>
408where
409    I: FpdecInner + Signed,
410{
411    type Output = Self;
412    fn neg(self) -> Self::Output {
413        Self(-self.0)
414    }
415}
416
417impl<I, const S: i32> ops::Add for ConstScaleFpdec<I, S>
418where
419    I: FpdecInner,
420{
421    type Output = Self;
422    fn add(self, rhs: Self) -> Self::Output {
423        Self(self.0 + rhs.0)
424    }
425}
426
427impl<I, const S: i32> ops::Sub for ConstScaleFpdec<I, S>
428where
429    I: FpdecInner,
430{
431    type Output = Self;
432    fn sub(self, rhs: Self) -> Self::Output {
433        Self(self.0 - rhs.0)
434    }
435}
436
437/// Performs the `*` operation bewteen 2 decimals.
438///
439/// The right operand may have different types (both underlying integer
440/// and scale), but the result inherits the left operand's type. If you
441/// want specify result's scale, please use [`Self::checked_mul`] directly.
442///
443/// # Panics
444///
445/// If [`Self::checked_mul`] returns `None`.
446///
447/// # Examples
448///
449/// ```
450/// use primitive_fixed_point_decimal::{ConstScaleFpdec, fpdec};
451/// type Balance = ConstScaleFpdec<i64, 4>;
452/// type FeeRate = ConstScaleFpdec<i16, 6>; // different types
453///
454/// let balance: Balance = fpdec!(12.60);
455/// let rate: FeeRate = fpdec!(0.01);
456///
457/// assert_eq!(balance * rate, fpdec!(0.126));
458/// ```
459impl<I, J, const S: i32, const S2: i32> ops::Mul<ConstScaleFpdec<J, S2>> for ConstScaleFpdec<I, S>
460where
461    I: FpdecInner,
462    J: FpdecInner,
463{
464    type Output = Self;
465    fn mul(self, rhs: ConstScaleFpdec<J, S2>) -> Self::Output {
466        self.checked_mul(rhs)
467            .expect("overflow in decimal multiplication")
468    }
469}
470
471/// Performs the `*` operation with an integer.
472///
473/// # Panics
474///
475/// If [`Self::checked_mul_int`] returns `None`.
476impl<I, J, const S: i32> ops::Mul<J> for ConstScaleFpdec<I, S>
477where
478    I: FpdecInner,
479    J: Into<I> + Num, // the `Num` to avoid conflicting implementations only
480{
481    type Output = Self;
482    fn mul(self, rhs: J) -> Self::Output {
483        self.checked_mul_int(rhs)
484            .expect("overflow in decimal multiplication")
485    }
486}
487
488/// Performs the `/` operation bewteen 2 decimals.
489///
490/// The right operand may have different types (both underlying integer
491/// and scale), but the result inherits the left operand's type. If you
492/// want specify result's scale, please use [`Self::checked_div`] directly.
493///
494/// # Panics
495///
496/// If [`Self::checked_div`] returns `None`.
497///
498/// # Examples
499///
500/// ```
501/// use primitive_fixed_point_decimal::{ConstScaleFpdec, fpdec};
502/// type Balance = ConstScaleFpdec<i64, 4>;
503/// type FeeRate = ConstScaleFpdec<i16, 6>; // different types
504///
505/// let fee: Balance = fpdec!(0.1260);
506/// let rate: FeeRate = fpdec!(0.01);
507///
508/// assert_eq!(fee / rate, fpdec!(12.6));
509/// ```
510impl<I, J, const S: i32, const S2: i32> ops::Div<ConstScaleFpdec<J, S2>> for ConstScaleFpdec<I, S>
511where
512    I: FpdecInner,
513    J: FpdecInner,
514{
515    type Output = Self;
516    fn div(self, rhs: ConstScaleFpdec<J, S2>) -> Self::Output {
517        self.checked_div(rhs).expect("fail in decimal division")
518    }
519}
520
521/// Performs the `/` operation with an integer.
522///
523/// # Panics
524///
525/// If [`Self::checked_div_int`] returns `None`.
526impl<I, J, const S: i32> ops::Div<J> for ConstScaleFpdec<I, S>
527where
528    I: FpdecInner,
529    J: Into<I> + Num,
530{
531    type Output = Self;
532    fn div(self, rhs: J) -> Self::Output {
533        self.checked_div_int(rhs).expect("fail in decimal division")
534    }
535}
536
537impl<I, const S: i32> ops::AddAssign for ConstScaleFpdec<I, S>
538where
539    I: FpdecInner,
540{
541    fn add_assign(&mut self, rhs: Self) {
542        self.0 += rhs.0;
543    }
544}
545
546impl<I, const S: i32> ops::SubAssign for ConstScaleFpdec<I, S>
547where
548    I: FpdecInner,
549{
550    fn sub_assign(&mut self, rhs: Self) {
551        self.0 -= rhs.0;
552    }
553}
554
555impl<I, J, const S: i32, const S2: i32> ops::MulAssign<ConstScaleFpdec<J, S2>>
556    for ConstScaleFpdec<I, S>
557where
558    I: FpdecInner,
559    J: FpdecInner,
560{
561    fn mul_assign(&mut self, rhs: ConstScaleFpdec<J, S2>) {
562        *self = *self * rhs;
563    }
564}
565
566impl<I, J, const S: i32> ops::MulAssign<J> for ConstScaleFpdec<I, S>
567where
568    I: FpdecInner,
569    J: Into<I> + Num,
570{
571    fn mul_assign(&mut self, rhs: J) {
572        *self = *self * rhs;
573    }
574}
575
576impl<I, J, const S: i32, const S2: i32> ops::DivAssign<ConstScaleFpdec<J, S2>>
577    for ConstScaleFpdec<I, S>
578where
579    I: FpdecInner,
580    J: FpdecInner,
581{
582    fn div_assign(&mut self, rhs: ConstScaleFpdec<J, S2>) {
583        *self = *self / rhs;
584    }
585}
586
587impl<I, J, const S: i32> ops::DivAssign<J> for ConstScaleFpdec<I, S>
588where
589    I: FpdecInner,
590    J: Into<I> + Num,
591{
592    fn div_assign(&mut self, rhs: J) {
593        *self = *self / rhs;
594    }
595}
596
597impl<I, J, const S: i32> IntoRatioInt<J> for ConstScaleFpdec<I, S>
598where
599    I: FpdecInner + Into<J>,
600{
601    fn to_int(self) -> J {
602        self.mantissa().into()
603    }
604}
605
606#[cfg(feature = "serde")]
607use serde::{Deserialize, Deserializer, Serialize, Serializer};
608
609#[cfg(feature = "serde")]
610impl<I, const S0: i32> Serialize for ConstScaleFpdec<I, S0>
611where
612    I: FpdecInner + fmt::Display,
613{
614    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
615    where
616        S: Serializer,
617    {
618        // XXX how to selete dump type?
619        if serializer.is_human_readable() {
620            serializer.collect_str(self)
621        } else {
622            Into::<f64>::into(*self).serialize(serializer)
623        }
624    }
625}
626
627#[cfg(feature = "serde")]
628impl<'de, I, const S: i32> Deserialize<'de> for ConstScaleFpdec<I, S>
629where
630    I: FromPrimitive + FpdecInner + Num<FromStrRadixErr = ParseIntError>,
631{
632    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
633    where
634        D: Deserializer<'de>,
635    {
636        use core::marker::PhantomData;
637        use core::str::FromStr;
638        use serde::de::{self, Visitor};
639
640        struct ConstScaleFpdecVistor<I, const S: i32>(PhantomData<I>);
641
642        macro_rules! visit_num {
643            ($func_name:ident, $num_type:ty) => {
644                fn $func_name<E: de::Error>(self, n: $num_type) -> Result<Self::Value, E> {
645                    ConstScaleFpdec::try_from(n).map_err(|_| E::custom("decimal overflow"))
646                }
647            };
648        }
649
650        impl<'de, I, const S: i32> Visitor<'de> for ConstScaleFpdecVistor<I, S>
651        where
652            I: FromPrimitive + FpdecInner + Num<FromStrRadixErr = ParseIntError>,
653        {
654            type Value = ConstScaleFpdec<I, S>;
655
656            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
657                write!(formatter, "decimal")
658            }
659
660            fn visit_str<E: de::Error>(self, s: &str) -> Result<Self::Value, E> {
661                ConstScaleFpdec::from_str(s).map_err(E::custom)
662            }
663
664            visit_num!(visit_f32, f32);
665            visit_num!(visit_f64, f64);
666            visit_num!(visit_i8, i8);
667            visit_num!(visit_i16, i16);
668            visit_num!(visit_i32, i32);
669            visit_num!(visit_i64, i64);
670            visit_num!(visit_i128, i128);
671            visit_num!(visit_u8, u8);
672            visit_num!(visit_u16, u16);
673            visit_num!(visit_u32, u32);
674            visit_num!(visit_u64, u64);
675            visit_num!(visit_u128, u128);
676        }
677
678        deserializer.deserialize_any(ConstScaleFpdecVistor(PhantomData))
679    }
680}
681
682#[cfg(test)]
683mod tests {
684    use super::*;
685    use crate as primitive_fixed_point_decimal;
686    use crate::fpdec;
687
688    #[test]
689    fn test_mul() {
690        let two_p12: ConstScaleFpdec<i32, 12> = fpdec!(2e-12);
691        let two_n12: ConstScaleFpdec<i32, -12> = fpdec!(2e+12);
692        let two_p6: ConstScaleFpdec<i32, 6> = fpdec!(2e-6);
693        let two_n6: ConstScaleFpdec<i32, -6> = fpdec!(2e+6);
694        let two_p3: ConstScaleFpdec<i32, 3> = fpdec!(2e-3);
695        let two_n3: ConstScaleFpdec<i32, -3> = fpdec!(2e+3);
696        let two_0: ConstScaleFpdec<i32, 0> = fpdec!(2);
697
698        let zero_p6 = ConstScaleFpdec::<i32, 6>::ZERO;
699        let zero_n6 = ConstScaleFpdec::<i32, -6>::ZERO;
700
701        let four_p12: ConstScaleFpdec<i32, 12> = fpdec!(4e-12);
702        let four_n12: ConstScaleFpdec<i32, -12> = fpdec!(4e+12);
703        let four_p6: ConstScaleFpdec<i32, 6> = fpdec!(4e-6);
704        let four_n6: ConstScaleFpdec<i32, -6> = fpdec!(4e+6);
705        let four_p3: ConstScaleFpdec<i32, 3> = fpdec!(4e-3);
706        let four_n3: ConstScaleFpdec<i32, -3> = fpdec!(4e+3);
707        let four_0: ConstScaleFpdec<i32, 0> = fpdec!(4);
708
709        assert_eq!(two_p12.mantissa(), 2);
710        assert_eq!(two_n12.mantissa(), 2);
711        assert_eq!(two_p6.mantissa(), 2);
712        assert_eq!(two_n6.mantissa(), 2);
713        assert_eq!(two_p3.mantissa(), 2);
714        assert_eq!(two_n3.mantissa(), 2);
715        assert_eq!(two_0.mantissa(), 2);
716        assert_eq!(zero_p6.mantissa(), 0);
717        assert_eq!(zero_n6.mantissa(), 0);
718
719        // S + S2 = SR
720        assert_eq!(two_p3.checked_mul(two_p3), Some(four_p6));
721        assert_eq!(two_n3.checked_mul(two_n3), Some(four_n6));
722        assert_eq!(two_p6.checked_mul(two_p6), Some(four_p12));
723        assert_eq!(two_n6.checked_mul(two_n6), Some(four_n12));
724        assert_eq!(two_0.checked_mul(two_p6), Some(four_p6));
725        assert_eq!(two_0.checked_mul(two_n6), Some(four_n6));
726        assert_eq!(two_n6.checked_mul(two_p6), Some(four_0));
727
728        // S + S2 > SR
729        assert_eq!(two_p6.checked_mul(two_p6), Some(zero_p6));
730        assert_eq!(two_p6.checked_mul(two_p3), Some(zero_p6));
731        assert_eq!(two_n6.checked_mul(two_p3), Some(zero_n6));
732        assert_eq!(two_n12.checked_mul(two_p12), Some(zero_n6));
733
734        // S + S2 < SR
735        assert_eq!(two_p6.checked_mul(two_p3), four_p12.checked_mul_int(1000));
736        assert_eq!(two_p6.checked_mul(two_0), four_p12.checked_mul_int(1000000));
737        assert_eq!(two_n6.checked_mul(two_n3), four_n3.checked_mul_int(1000000));
738        assert_eq!(two_n6.checked_mul(two_p3), four_p3.checked_mul_int(1000000));
739        assert_eq!(two_p6.checked_mul(two_n3), four_p6.checked_mul_int(1000));
740        assert_eq!(two_n12.checked_mul(two_p12), four_p3.checked_mul_int(1000));
741
742        // S + S2 - SR > 9
743        assert_eq!(two_p6.checked_mul::<_, 6, 0>(two_p6), None);
744        assert_eq!(two_p12.checked_mul::<_, 6, 6>(two_p6), None);
745        assert_eq!(two_p6.checked_mul::<_, -6, -10>(two_n6), None);
746
747        // S + S2 - SR < -9
748        assert_eq!(two_n6.checked_mul::<_, -6, 0>(two_n6), None);
749        assert_eq!(two_n12.checked_mul::<_, -6, -6>(two_n6), None);
750        assert_eq!(two_n6.checked_mul::<_, 6, 10>(two_p6), None);
751    }
752
753    #[test]
754    fn test_mul_overflow() {
755        let max_p6 = ConstScaleFpdec::<i32, 6>::MAX;
756        let min_p6 = ConstScaleFpdec::<i32, 6>::MIN;
757        let ten_p6: ConstScaleFpdec<i32, 6> = fpdec!(10);
758        let half_min_p6 = ConstScaleFpdec::<i32, 6>::MIN.checked_div_int(2).unwrap();
759        let half_max_p6 = ConstScaleFpdec::<i32, 6>::MAX
760            .checked_div_int_ext(2, Rounding::Floor)
761            .unwrap();
762
763        let max_p5 = ConstScaleFpdec::<i32, 5>::MAX;
764        let min_p5 = ConstScaleFpdec::<i32, 5>::MIN;
765
766        assert_eq!(max_p6.checked_mul_int(2), None);
767        assert_eq!(min_p6.checked_mul_int(2), None);
768        assert_eq!(half_min_p6.checked_mul_int(2), Some(min_p6));
769        assert_eq!(
770            half_max_p6.checked_mul_int(2),
771            max_p6.checked_sub(fpdec!(1e-6))
772        );
773
774        assert_eq!(max_p6.checked_mul(ten_p6), Some(max_p5));
775        assert_eq!(min_p6.checked_mul(ten_p6), Some(min_p5));
776
777        // mantissa overflow
778        assert_eq!(max_p6.checked_mul::<_, 6, 6>(max_p6), None);
779        assert_eq!(max_p6.checked_mul::<_, 6, 6>(ten_p6), None);
780        assert_eq!(half_max_p6.checked_mul::<_, 6, 6>(ten_p6), None);
781        assert_eq!(min_p6.checked_mul::<_, 6, 6>(min_p6), None);
782        assert_eq!(min_p6.checked_mul::<_, 6, 6>(ten_p6), None);
783        assert_eq!(half_min_p6.checked_mul::<_, 6, 6>(ten_p6), None);
784
785        // diff_scale out of range [-9, 9]
786        assert_eq!(max_p6.checked_mul::<_, 6, 2>(max_p6), None);
787        assert_eq!(ten_p6.checked_mul::<_, 6, 2>(ten_p6), None);
788        assert_eq!(max_p6.checked_mul::<_, 6, -22>(max_p6), None);
789        assert_eq!(ten_p6.checked_mul::<_, 6, -22>(ten_p6), None);
790    }
791
792    #[test]
793    fn test_div() {
794        let two_p12: ConstScaleFpdec<i32, 12> = fpdec!(2e-12);
795        let two_n12: ConstScaleFpdec<i32, -12> = fpdec!(2e+12);
796        let two_p6: ConstScaleFpdec<i32, 6> = fpdec!(2e-6);
797        let two_n6: ConstScaleFpdec<i32, -6> = fpdec!(2e+6);
798        let two_p3: ConstScaleFpdec<i32, 3> = fpdec!(2e-3);
799        let two_n3: ConstScaleFpdec<i32, -3> = fpdec!(2e+3);
800        let two_0: ConstScaleFpdec<i32, 0> = fpdec!(2);
801
802        let zero_p6 = ConstScaleFpdec::<i32, 6>::ZERO;
803        let zero_n6 = ConstScaleFpdec::<i32, -6>::ZERO;
804
805        let four_p12: ConstScaleFpdec<i32, 12> = fpdec!(4e-12);
806        let four_n12: ConstScaleFpdec<i32, -12> = fpdec!(4e+12);
807        let four_p6: ConstScaleFpdec<i32, 6> = fpdec!(4e-6);
808        let four_n6: ConstScaleFpdec<i32, -6> = fpdec!(4e+6);
809        let four_p3: ConstScaleFpdec<i32, 3> = fpdec!(4e-3);
810        let four_n3: ConstScaleFpdec<i32, -3> = fpdec!(4e+3);
811        let four_0: ConstScaleFpdec<i32, 0> = fpdec!(4);
812
813        // S - S2 = SR
814        assert_eq!(four_p3.checked_div(two_p3), Some(two_0));
815        assert_eq!(four_n3.checked_div(two_n3), Some(two_0));
816        assert_eq!(four_p12.checked_div(two_p6), Some(two_p6));
817        assert_eq!(four_n6.checked_div(two_n12), Some(two_p6));
818        assert_eq!(four_0.checked_div(two_p6), Some(two_n6));
819        assert_eq!(four_0.checked_div(two_n6), Some(two_p6));
820        assert_eq!(four_n6.checked_div(two_p6), Some(two_n12));
821
822        // S - S2 > SR
823        assert_eq!(four_p6.checked_div(two_p6), Some(zero_n6));
824        assert_eq!(four_p12.checked_div(two_p3), Some(zero_p6));
825        assert_eq!(four_p6.checked_div(two_n3), Some(zero_p6));
826
827        // S - S2 < SR
828        assert_eq!(four_p6.checked_div(two_p3), two_p6.checked_mul_int(1000));
829        assert_eq!(four_p6.checked_div(two_0), two_p12.checked_mul_int(1000000));
830        assert_eq!(four_n6.checked_div(two_n3), two_0.checked_mul_int(1000));
831        assert_eq!(four_n6.checked_div(two_p3), two_n6.checked_mul_int(1000));
832        assert_eq!(four_p6.checked_div(two_n3), two_p12.checked_mul_int(1000));
833
834        // S - S2 - SR > 9
835        assert_eq!(four_p6.checked_div::<_, 6, -10>(two_p6), None);
836        assert_eq!(four_p12.checked_div::<_, 6, -6>(two_p6), None);
837        assert_eq!(four_p6.checked_div::<_, -6, 0>(two_n6), None);
838
839        // S - S2 - SR < -9
840        assert_eq!(four_n6.checked_div::<_, -6, 10>(two_n6), None);
841        assert_eq!(four_n12.checked_div::<_, -6, 6>(two_n6), None);
842        assert_eq!(four_n6.checked_div::<_, 6, 0>(two_p6), None);
843    }
844
845    #[test]
846    fn test_div_overflow() {
847        let max_p6 = ConstScaleFpdec::<i32, 6>::MAX;
848        let min_p6 = ConstScaleFpdec::<i32, 6>::MIN;
849        let cent_p6: ConstScaleFpdec<i32, 6> = fpdec!(0.1);
850        let half_min_p6 = ConstScaleFpdec::<i32, 6>::MIN.checked_div_int(2).unwrap();
851        let half_max_p6 = ConstScaleFpdec::<i32, 6>::MAX
852            .checked_div_int_ext(2, Rounding::Floor)
853            .unwrap();
854
855        let max_p5 = ConstScaleFpdec::<i32, 5>::MAX;
856        let min_p5 = ConstScaleFpdec::<i32, 5>::MIN;
857
858        assert_eq!(max_p6.checked_div(cent_p6), Some(max_p5));
859        assert_eq!(min_p6.checked_div(cent_p6), Some(min_p5));
860
861        // mantissa overflow
862        assert_eq!(max_p6.checked_div::<_, 6, 6>(cent_p6), None);
863        assert_eq!(half_max_p6.checked_div::<_, 6, 6>(cent_p6), None);
864        assert_eq!(min_p6.checked_div::<_, 6, 6>(cent_p6), None);
865        assert_eq!(half_min_p6.checked_div::<_, 6, 6>(cent_p6), None);
866
867        // diff_scale out of range [-9, 9]
868        assert_eq!(max_p6.checked_div::<_, 6, 10>(max_p6), None);
869        assert_eq!(cent_p6.checked_div::<_, 6, 10>(cent_p6), None);
870        assert_eq!(max_p6.checked_div::<_, 6, -10>(max_p6), None);
871        assert_eq!(cent_p6.checked_div::<_, 6, -10>(cent_p6), None);
872    }
873
874    type Dec32p2 = ConstScaleFpdec<i32, 2>;
875    type Dec32n2 = ConstScaleFpdec<i32, -2>;
876    #[test]
877    fn test_from_int() {
878        assert_eq!(Dec32p2::try_from(1_i16).unwrap().mantissa(), 100);
879        assert_eq!(Dec32p2::try_from(i32::MAX), Err(ParseError::Overflow));
880
881        // avoid overflow for: i16::MAX * 100
882        assert_eq!(
883            Dec32p2::try_from(i16::MAX).unwrap().mantissa(),
884            i16::MAX as i32 * 100
885        );
886
887        // avoid overflow for: i32::MAX * 100
888        assert_eq!(
889            Dec32n2::try_from(i32::MAX as i64 * 100).unwrap().mantissa(),
890            i32::MAX
891        );
892
893        // overflow
894        assert_eq!(Dec32p2::try_from(i32::MAX), Err(ParseError::Overflow));
895        assert_eq!(
896            Dec32n2::try_from(i32::MAX as i64 * 1000),
897            Err(ParseError::Overflow)
898        );
899    }
900
901    #[test]
902    fn test_from_float() {
903        assert_eq!(Dec32p2::try_from(3.1415).unwrap().mantissa(), 314);
904        assert_eq!(Dec32n2::try_from(31415.16).unwrap().mantissa(), 314);
905
906        assert_eq!(Dec32p2::try_from(3.14e10), Err(ParseError::Overflow));
907        assert_eq!(Dec32n2::try_from(3.14e16), Err(ParseError::Overflow));
908    }
909
910    #[test]
911    fn test_fmt() {
912        // FromStr
913        assert_eq!(Dec32p2::from_str("0"), Ok(fpdec!(0)));
914        assert_eq!(Dec32p2::from_str("1000"), Ok(fpdec!(1000)));
915        assert_eq!(Dec32p2::from_str("-1000"), Ok(fpdec!(-1000)));
916        assert_eq!(Dec32p2::from_str("0.12"), Ok(fpdec!(0.12)));
917        assert_eq!(Dec32p2::from_str("-0.12"), Ok(fpdec!(-0.12)));
918        assert_eq!(Dec32p2::from_str("3.14"), Ok(fpdec!(3.14)));
919        assert_eq!(Dec32p2::from_str("-3.14"), Ok(fpdec!(-3.14)));
920        assert_eq!(Dec32p2::from_str("3.1415"), Err(ParseError::Precision));
921
922        assert_eq!(Dec32n2::from_str("1000"), Ok(fpdec!(1000)));
923        assert_eq!(Dec32n2::from_str("-1000"), Ok(fpdec!(-1000)));
924        assert_eq!(Dec32n2::from_str("1000.00"), Err(ParseError::Precision));
925        assert_eq!(Dec32n2::from_str("1001"), Err(ParseError::Precision));
926    }
927
928    // used for testing format
929    struct Buffer {
930        data: [u8; 100],
931        len: usize,
932    }
933    impl Buffer {
934        fn new() -> Self {
935            Buffer {
936                data: [0; 100],
937                len: 0,
938            }
939        }
940        fn as_str(&self) -> &str {
941            unsafe { core::str::from_utf8_unchecked(&self.data[..self.len]) }
942        }
943    }
944    use core::fmt::Write;
945    impl Write for Buffer {
946        fn write_str(&mut self, s: &str) -> fmt::Result {
947            let bytes = s.as_bytes();
948            if self.len + bytes.len() > self.data.len() {
949                return Err(fmt::Error);
950            }
951            self.data[self.len..self.len + bytes.len()].copy_from_slice(bytes);
952            self.len += bytes.len();
953            Ok(())
954        }
955    }
956
957    type Dec64p7 = ConstScaleFpdec<i64, 7>;
958    fn do_check_fmt(f: f64) {
959        let mut buf = Buffer::new();
960        let dec: Dec64p7 = fpdec!(f);
961        write!(buf, "{dec}").unwrap();
962        let dec2: Dec64p7 = Dec64p7::from_str(buf.as_str()).unwrap();
963        assert_eq!(dec, dec2);
964
965        //
966        let mut buf = Buffer::new();
967        let dec: Dec64p7 = fpdec!(-f);
968        write!(buf, "{dec:.7}").unwrap();
969        let dec2: Dec64p7 = Dec64p7::from_str(buf.as_str()).unwrap();
970        assert_eq!(dec, dec2);
971
972        //
973        let mut buf = Buffer::new();
974        let dec: Dec64p7 = fpdec!(-f);
975        write!(buf, "{dec}").unwrap();
976        let dec2: Dec64p7 = Dec64p7::from_str(buf.as_str()).unwrap();
977        assert_eq!(dec, dec2);
978    }
979
980    #[test]
981    fn test_fmt2() {
982        do_check_fmt(0.0);
983        do_check_fmt(1.0);
984        do_check_fmt(123.0);
985        do_check_fmt(123.456);
986        do_check_fmt(123.4567);
987        do_check_fmt(123.002);
988        do_check_fmt(123.00002);
989        do_check_fmt(123.0000002);
990        do_check_fmt(0.456);
991        do_check_fmt(0.4567);
992        do_check_fmt(0.002);
993        do_check_fmt(0.00002);
994        do_check_fmt(0.0000002);
995    }
996}