#![no_std]
#![doc = include_str!("../README.md")]
mod convert;
mod display;
mod from_str;
mod ops;
mod int128;
mod int32;
mod int64;
use core::fmt::{Debug, Display};
use core::ops::{Add, AddAssign, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub, SubAssign};
pub use from_str::ParseError;
pub type Dec128 = Decimal<u128, true>;
pub type UDec128 = Decimal<u128, false>;
pub type Dec64 = Decimal<u64, true>;
pub type UDec64 = Decimal<u64, false>;
pub type Dec32 = Decimal<u32, true>;
pub type UDec32 = Decimal<u32, false>;
#[derive(Copy, Clone, Default)]
#[repr(transparent)]
pub struct Decimal<I: UnderlyingInt, const S: bool>(I);
pub trait UnderlyingInt:
Sized
+ Clone
+ Copy
+ Debug
+ Display
+ PartialEq
+ Eq
+ PartialOrd
+ Ord
+ Add<Output = Self>
+ Sub<Output = Self>
+ Div<Output = Self>
+ Rem<Output = Self>
+ Mul<Output = Self>
+ Shl<u32, Output = Self>
+ Shr<u32, Output = Self>
+ BitOr<Output = Self>
+ BitAnd<Output = Self>
+ BitXor<Output = Self>
+ AddAssign
+ SubAssign
{
const MAX: Self;
const ZERO: Self;
const ONE: Self;
const TEN: Self;
const HUNDRED: Self;
const UNSIGNED_MAX_MATISSA: Self;
const SIGNED_MAX_MATISSA: Self;
const SIGNED_MIN_UNDERINT: Self;
const BITS: u32;
const SCALE_BITS: u32;
const MAX_SCALE: u32 = 2_u32.pow(Self::SCALE_BITS) - 1;
type Signed: Display;
fn to_signed(self, sign: u8) -> Self::Signed;
fn from_signed(s: Self::Signed) -> (Self, u8);
fn as_u32(self) -> u32;
fn from_u32(n: u32) -> Self;
fn leading_zeros(self) -> u32;
fn mul_exp(self, iexp: u32) -> Self;
fn checked_mul_exp(self, iexp: u32) -> Option<Self>;
fn div_exp(self, iexp: u32) -> Self;
fn div_rem_exp(self, iexp: u32) -> (Self, Self);
fn mul_with_sum_scale<const S: bool>(self, right: Self, sum_scale: u32) -> Option<(Self, u32)>;
fn div_with_scales<const S: bool>(
self,
d: Self,
s_scale: u32,
d_scale: u32,
) -> Option<(Self, u32)>;
}
impl<I: UnderlyingInt, const S: bool> Decimal<I, S> {
pub const ZERO: Self = Self(I::ZERO);
pub const ONE: Self = Self(I::ONE);
const META_BITS: u32 = (S as u32) + I::SCALE_BITS;
const MANTISSA_BITS: u32 = I::BITS - Self::META_BITS;
fn unpack(self) -> (u8, u32, I) {
if S {
let mantissa = self.0 & I::SIGNED_MAX_MATISSA;
let meta = (self.0 >> Self::MANTISSA_BITS).as_u32();
let scale = meta & ((1 << I::SCALE_BITS) - 1);
let sign = meta >> I::SCALE_BITS;
(sign as u8, scale, mantissa)
} else {
let mantissa = self.0 & I::UNSIGNED_MAX_MATISSA;
let scale = (self.0 >> Self::MANTISSA_BITS).as_u32();
(0, scale, mantissa)
}
}
fn pack(sign: u8, scale: u32, mantissa: I) -> Self {
let meta = if S {
debug_assert!(sign <= 1);
debug_assert!(scale <= I::MAX_SCALE);
debug_assert!(Self::valid_mantissa(mantissa));
((sign as u32) << I::SCALE_BITS) | scale
} else {
debug_assert!(sign == 0);
debug_assert!(scale <= I::MAX_SCALE);
debug_assert!(Self::valid_mantissa(mantissa));
scale
};
Self(I::from_u32(meta) << Self::MANTISSA_BITS | mantissa)
}
fn valid_mantissa(man: I) -> bool {
man <= (I::MAX >> Self::META_BITS)
}
pub const fn underlying(self) -> I {
self.0
}
pub const fn from_underlying(i: I) -> Self {
Self(i)
}
}
impl<I: UnderlyingInt> Decimal<I, true> {
pub const MAX: Self = Self(I::SIGNED_MAX_MATISSA);
pub const MIN: Self = Self(I::SIGNED_MIN_UNDERINT);
pub fn parts(self) -> (I::Signed, u32) {
let (sign, scale, man) = self.unpack();
(I::to_signed(man, sign), scale)
}
pub fn from_parts<S>(mantissa: S, scale: u32) -> Self
where
S: Into<I::Signed>,
{
Self::try_from_parts(mantissa, scale).expect("invalid decimal input parts")
}
pub fn try_from_parts<S>(mantissa: S, scale: u32) -> Option<Self>
where
S: Into<I::Signed>,
{
if scale > I::MAX_SCALE {
return None;
}
let (man, sign) = I::from_signed(mantissa.into());
if man > I::SIGNED_MAX_MATISSA {
return None;
}
Some(Self::pack(sign, scale, man))
}
}
impl<I: UnderlyingInt> Decimal<I, false> {
pub const MAX: Self = Self(I::UNSIGNED_MAX_MATISSA);
pub const MIN: Self = Self::ZERO;
pub fn parts(self) -> (I, u32) {
let (_, scale, man) = self.unpack();
(man, scale)
}
pub fn from_parts(mantissa: I, scale: u32) -> Self {
Self::try_from_parts(mantissa, scale).expect("invalid decimal input parts")
}
pub fn try_from_parts(mantissa: I, scale: u32) -> Option<Self> {
if scale > I::MAX_SCALE {
return None;
}
if mantissa > I::UNSIGNED_MAX_MATISSA {
return None;
}
Some(Self::pack(0, scale, mantissa))
}
}
pub(crate) fn bits_to_digits(bits: u32) -> u32 {
bits * 1233 >> 12 }