1#![no_std]
2#![doc = include_str!("../README.md")]
3
4mod display;
5mod from_str;
6mod ops;
7
8mod int128;
9use core::fmt::{Debug, Display};
13use core::ops::{Add, AddAssign, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub, SubAssign};
14
15pub use from_str::ParseError;
16
17pub type Dec128 = Decimal<u128>;
19
20#[derive(Copy, Clone, Default)]
26#[repr(transparent)]
27pub struct Decimal<I: UnderlyingInt>(I);
28
29pub trait UnderlyingInt:
31 Sized
32 + Clone
33 + Copy
34 + Debug
35 + Display
36 + PartialEq
37 + Eq
38 + PartialOrd
39 + Ord
40 + Add<Output = Self>
41 + Sub<Output = Self>
42 + Div<Output = Self>
43 + Rem<Output = Self>
44 + Mul<Output = Self>
45 + Shl<u32, Output = Self>
46 + Shr<u32, Output = Self>
47 + BitOr<Output = Self>
48 + BitAnd<Output = Self>
49 + BitXor<Output = Self>
50 + AddAssign
51 + SubAssign
52{
53 const ZERO: Self;
54 const ONE: Self;
55 const TEN: Self;
56 const HUNDRED: Self;
57 const MAX_MATISSA: Self;
58 const MIN_UNDERINT: Self;
59
60 const BITS: u32;
61 const MAX_SCALE: u32;
62 const SCALE_BITS: u32 = (Self::MAX_SCALE * 2 - 1).ilog2();
63 const META_BITS: u32 = 1 + Self::SCALE_BITS;
64 const MATISSA_BITS: u32 = Self::BITS - Self::META_BITS;
65
66 type Signed: Display;
67
68 fn to_signed(self, sign: u8) -> Self::Signed;
70 fn from_signed(s: Self::Signed) -> (Self, u8);
71
72 fn as_u32(self) -> u32;
74 fn from_u32(n: u32) -> Self;
75
76 fn leading_zeros(self) -> u32;
77
78 fn mul_exp(self, iexp: u32) -> Self;
80
81 fn checked_mul_exp(self, iexp: u32) -> Option<Self>;
83
84 fn div_exp(self, iexp: u32) -> Self;
87
88 fn div_rem_exp(self, iexp: u32) -> (Self, Self);
90
91 fn mul_with_sum_scale(self, right: Self, sum_scale: u32) -> Option<(Self, u32)>;
93
94 fn div_with_scales(self, d: Self, s_scale: u32, d_scale: u32) -> Option<(Self, u32)>;
96}
97
98impl<I: UnderlyingInt> Decimal<I> {
99 pub const ZERO: Self = Self(I::ZERO);
101
102 pub const MAX: Self = Self(I::MAX_MATISSA);
106
107 pub const MIN: Self = Self(I::MIN_UNDERINT);
109
110 fn unpack(self) -> (u8, u32, I) {
115 let mantissa = self.0 & I::MAX_MATISSA;
116 let meta = (self.0 >> I::MATISSA_BITS).as_u32();
117 let scale = meta & ((1 << I::SCALE_BITS) - 1);
118 let sign = meta >> I::SCALE_BITS;
119 (sign as u8, scale, mantissa)
120 }
121
122 fn pack(sign: u8, scale: u32, mantissa: I) -> Self {
124 debug_assert!(sign <= 1);
125 debug_assert!(scale <= I::MAX_SCALE);
126 debug_assert!(mantissa <= I::MAX_MATISSA);
127
128 let meta = ((sign as u32) << I::SCALE_BITS) | scale;
129 Self(I::from_u32(meta) << I::MATISSA_BITS | mantissa)
130 }
131
132 pub fn parts(self) -> (I::Signed, u32) {
144 let (sign, scale, man) = self.unpack();
145 (I::to_signed(man, sign), scale)
146 }
147
148 pub fn from_parts<S>(mantissa: S, scale: u32) -> Self
163 where
164 S: Into<I::Signed>,
165 {
166 Self::try_from_parts(mantissa, scale).expect("invalid decimal input parts")
167 }
168
169 pub fn try_from_parts<S>(mantissa: S, scale: u32) -> Option<Self>
184 where
185 S: Into<I::Signed>,
186 {
187 if scale > I::MAX_SCALE {
188 return None;
189 }
190 let (man, sign) = I::from_signed(mantissa.into());
191 if man > I::MAX_MATISSA {
192 return None;
193 }
194 Some(Self::pack(sign, scale, man))
195 }
196
197 pub const fn underlying(self) -> I {
202 self.0
203 }
204
205 pub fn from_underlying(ui: I) -> Self {
211 Self::try_from_underlying(ui).expect("invalid underlying integer")
212 }
213
214 pub fn try_from_underlying(ui: I) -> Option<Self> {
216 let meta = (ui >> I::MATISSA_BITS).as_u32();
217 let scale = meta & ((1 << I::SCALE_BITS) - 1);
218 if scale > I::MAX_SCALE {
219 None
220 } else {
221 Some(Self(ui))
222 }
223 }
224
225 pub const unsafe fn unchecked_from_underlying(ui: I) -> Self {
229 Self(ui)
230 }
231}
232
233macro_rules! convert_from_int {
234 ($decimal_int:ty, $decimal_signed:ty; $($from_int:ty),*) => {$(
235 impl From<$from_int> for Decimal<$decimal_int> {
236 fn from(value: $from_int) -> Self {
237 Self::from_parts(value as $decimal_signed, 0)
238 }
239 }
240 )*};
241}
242convert_from_int!(u128, i128; i8, u8, i16, u16, i32, u32, i64, u64);
243
244pub(crate) fn bits_to_digits(bits: u32) -> u32 {
245 bits * 1233 >> 12 }