rust_fixed_point_decimal/
lib.rs1#![doc = include_str!("../README.md")]
11#![allow(dead_code)]
12#![allow(incomplete_features)]
13#![feature(generic_const_exprs)]
14#![feature(associated_type_bounds)]
15#![feature(int_roundings)]
16#![warn(missing_docs)]
17
18#[doc(inline)]
19pub use binops::{div_rounded::DivRounded, mul_rounded::MulRounded};
20#[doc(inline)]
21pub use errors::*;
22#[doc(inline)]
23pub use rounding::{Round, RoundInto, RoundingMode};
24#[doc(inline)]
25pub use rust_fixed_point_decimal_core::{ParseDecimalError, MAX_PREC};
26#[doc(inline)]
27pub use rust_fixed_point_decimal_macros::Dec;
28
29use crate::prec_constraints::{PrecLimitCheck, True};
30
31mod binops;
32mod errors;
33mod format;
34mod from_decimal;
35mod from_float;
36mod from_int;
37mod from_str;
38mod rounding;
39mod unops;
40
41mod prec_constraints {
42 pub trait True {}
43
44 pub struct PrecLimitCheck<const CHECK: bool> {}
45
46 impl True for PrecLimitCheck<true> {}
47}
48
49#[derive(Copy, Clone, Eq, Ord)]
55#[repr(transparent)]
56pub struct Decimal<const P: u8>
57where
58 PrecLimitCheck<{ P <= MAX_PREC }>: True,
60{
61 coeff: i128,
62}
63
64impl<const P: u8> Decimal<P>
65where
66 PrecLimitCheck<{ P <= MAX_PREC }>: True,
67{
68 #[doc(hidden)]
70 #[inline(always)]
71 pub fn new_raw(val: i128) -> Self {
72 Self { coeff: val }
73 }
74
75 #[doc(hidden)]
77 #[inline(always)]
78 pub fn coefficient(self) -> i128 {
79 self.coeff
80 }
81
82 #[inline(always)]
84 pub const fn precision(self) -> u8 {
85 P
86 }
87
88 pub const ZERO: Decimal<P> = Decimal { coeff: 0i128 };
90 pub const ONE: Decimal<P> = Decimal {
92 coeff: 10i128.pow(P as u32),
93 };
94 pub const NEG_ONE: Decimal<P> = Decimal {
96 coeff: -(10i128.pow(P as u32)),
97 };
98 pub const TWO: Decimal<P> = Decimal {
100 coeff: 2i128 * 10i128.pow(P as u32),
101 };
102 pub const TEN: Decimal<P> = Decimal {
104 coeff: 10i128.pow((P + 1) as u32),
105 };
106 pub const MAX: Decimal<P> = Decimal { coeff: i128::MAX };
108 pub const MIN: Decimal<P> = Decimal { coeff: i128::MIN };
110 pub const DELTA: Decimal<P> = Decimal { coeff: 1i128 };
112}
113
114impl<const P: u8> Default for Decimal<P>
115where
116 PrecLimitCheck<{ P <= MAX_PREC }>: True,
117{
118 #[inline(always)]
120 fn default() -> Self {
121 Self::ZERO
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use crate::Decimal;
128
129 #[test]
130 fn test_new_raw() {
131 let val = 12345678901234567890_i128;
132 let d: Decimal<5> = Decimal::new_raw(val);
133 assert_eq!(d.coeff, val);
134 assert_eq!(d.precision(), 5);
135 let d: Decimal<9> = Decimal::new_raw(val);
136 assert_eq!(d.coeff, val);
137 assert_eq!(d.precision(), 9);
138 }
139
140 macro_rules! test_constants_and_default {
141 () => {test_constants_and_default!(0,1,2,7,9);};
142 ($($p:expr),*) => {
143 #[test]
144 fn test_consts() {
145 $(
146 assert_eq!(Decimal::<$p>::ZERO.coeff, 0i128);
147 assert_eq!(Decimal::<$p>::default().coeff, 0i128);
148 assert_eq!(Decimal::<$p>::ONE.coeff, 10i128.pow($p));
149 assert_eq!(Decimal::<$p>::NEG_ONE.coeff,
150 Decimal::<$p>::ONE.coeff.checked_neg().unwrap());
151 assert_eq!(Decimal::<$p>::TWO.coeff,
152 Decimal::<$p>::ONE.coeff * 2);
153 assert_eq!(Decimal::<$p>::TEN.coeff, 10i128.pow($p + 1));
154 assert_eq!(Decimal::<$p>::MAX.coeff, i128::MAX);
155 assert_eq!(Decimal::<$p>::MIN.coeff, i128::MIN);
156 assert_eq!(Decimal::<$p>::DELTA.coeff, 1i128);
157 )*
158 }
159 }
160 }
161
162 test_constants_and_default!();
163}