use std::char::from_digit;
use std::cmp::Ordering;
use std::error::Error;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
use std::str::FromStr;
use num_bigint::BigUint;
use num_traits::identities::{One, Zero};
use num_traits::ToPrimitive;
pub mod types;
const U64_MAX_DIGITS: u64 = 19u64;
const U64_MAX_DECIMAL: u64 = 10_000_000_000_000_000_000u64;
pub trait FixedScale {
const SCALE: u64;
}
pub trait RoundingMode {
fn round(int_value: BigUint, carrier: u8) -> BigUint;
}
pub struct RoundHalfUp {}
impl RoundingMode for RoundHalfUp{
#[inline]
fn round(int_value: BigUint, carrier: u8) -> BigUint {
int_value + if carrier >= 5u8 { 1u64 } else { 0u64 }
}
}
pub struct RoundDown {}
impl RoundingMode for RoundDown {
#[inline]
fn round(int_value: BigUint, _: u8) -> BigUint {
int_value
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct ParseError(String);
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {}", self.description(), self.0)
}
}
impl Error for ParseError {
fn description(&self) -> &str {
"Failed to parse fixed point decimal:"
}
fn cause(&self) -> Option<&dyn Error> {
None
}
}
#[derive(Clone)]
pub struct FixedUnsigned<S>
where S: FixedScale
{
int_value: BigUint,
scale: PhantomData<S>
}
impl<S> FixedUnsigned<S>
where S: FixedScale
{
fn new(int_value: BigUint) -> Self {
Self { int_value, scale: PhantomData }
}
fn scale_up(mut int_value: BigUint, mut scale: u64) -> BigUint {
while scale >= U64_MAX_DIGITS {
int_value *= U64_MAX_DECIMAL;
scale -= U64_MAX_DIGITS;
}
while scale > 0u64 {
int_value *= 10u64;
scale -= 1;
}
int_value
}
fn scale_down<R: RoundingMode>(mut int_value: BigUint, mut scale: u64) -> BigUint {
while scale >= U64_MAX_DIGITS {
int_value /= U64_MAX_DECIMAL;
scale -= U64_MAX_DIGITS;
}
while scale > 1u64 {
int_value /= 10u64;
scale -= 1;
}
if scale > 0u64 {
let carrier = (&int_value % 10u64).to_u8().unwrap();
int_value /= 10u64;
int_value = R::round(int_value, carrier);
}
int_value
}
pub fn int_part(&self) -> BigUint {
Self::scale_down::<RoundDown>(self.int_value.clone(), S::SCALE)
}
pub fn frac_part(&self) -> BigUint {
unimplemented!();
}
pub fn scale(&self) -> u64 {
S::SCALE
}
pub fn from_bytes_be(bytes: &[u8]) -> Self {
Self::new(BigUint::from_bytes_be(bytes))
}
pub fn from_bytes_le(bytes: &[u8]) -> Self {
Self::new(BigUint::from_bytes_be(bytes))
}
pub fn to_bytes_be(&self) -> Vec<u8> {
self.int_value.to_bytes_be()
}
pub fn to_bytes_le(&self) -> Vec<u8> {
self.int_value.to_bytes_le()
}
pub fn to_radix_string(&self, radix: u8, uppercase: bool) -> String {
if radix == 0 || radix > 36 {
panic!("Radix too large: {}", radix);
}
let digits = self.int_value.to_radix_be(u32::from(radix));
let mut string: String = String::new();
let decimal_place = digits.len().checked_sub(S::SCALE as usize);
if let Some(0) = decimal_place {
string.push('0');
}
for (i, d) in digits.iter().enumerate() {
match decimal_place {
Some(dp) if dp == i => string.push('.'),
_ => ()
}
let c = from_digit(u32::from(*d), u32::from(radix)).unwrap();
string.push(if uppercase { c.to_ascii_uppercase() } else { c });
}
string
}
pub fn from_radix_string(string: &str, radix: u8) -> Result<Self, ParseError> {
if radix == 0 || radix > 36 {
panic!("Radix too large: {}", radix);
}
let mut digits: Vec<u8> = Vec::new();
let mut decimal_place = None;
for (i, c) in string.chars().enumerate() {
if c == '.' {
if decimal_place.is_some() {
return Err(ParseError(String::from(string)))
}
decimal_place = Some(i)
}
else {
digits.push(c.to_digit(u32::from(radix)).unwrap() as u8)
}
}
if digits.is_empty() {
return Err(ParseError(String::from(string)));
}
let int_value = BigUint::from_radix_be(digits.as_slice(), u32::from(radix))
.ok_or_else(|| ParseError(String::from(string)))?;
let scale = decimal_place.map(|p| string.len() - p - 1).unwrap_or(0) as u64;
let int_value = if scale < S::SCALE {
Self::scale_up(int_value, S::SCALE - scale)
}
else if scale > S::SCALE {
Self::scale_down::<RoundDown>(int_value, scale - S::SCALE)
}
else {
int_value
};
Ok(Self::new(int_value))
}
fn from_biguint(int_value: BigUint) -> Self {
Self::new(Self::scale_up(int_value, S::SCALE))
}
pub fn into_biguint(self) -> BigUint {
Self::scale_down::<RoundDown>(self.int_value, S::SCALE)
}
pub fn into_biguint_without_scale(self) -> BigUint {
self.int_value
}
pub fn bits(&self) -> usize {
self.int_value.bits()
}
pub fn bytes(&self) -> usize {
let bits = self.bits();
bits / 8 + if bits % 8 == 0 {0} else {1}
}
#[inline]
fn add(a: &BigUint, b: &BigUint) -> BigUint {
a + b
}
#[inline]
fn sub(a: &BigUint, b: &BigUint) -> BigUint {
a - b
}
#[inline]
fn mul(a: &BigUint, b: &BigUint) -> BigUint {
Self::scale_down::<RoundHalfUp>((a * b).clone(), S::SCALE)
}
#[inline]
fn div(a: &BigUint, b: &BigUint) -> BigUint {
Self::scale_down::<RoundHalfUp>(Self::scale_up(a.clone(), S::SCALE + 1u64) / b, 1u64)
}
pub fn into_scale<T: FixedScale, R: RoundingMode>(self) -> FixedUnsigned<T> {
FixedUnsigned::<T>::new(if S::SCALE < T::SCALE {
Self::scale_up(self.int_value,T::SCALE - S::SCALE)
}
else {
Self::scale_down::<R>(self.int_value, S::SCALE - T::SCALE)
})
}
}
impl<S> Add for FixedUnsigned<S>
where S: FixedScale
{
type Output = Self;
fn add(self, rhs: FixedUnsigned<S>) -> Self::Output {
Self::new(Self::add(&(self.int_value), &(rhs.int_value)))
}
}
impl<'a, 'b, S> Add<&'b FixedUnsigned<S>> for &'a FixedUnsigned<S>
where S: FixedScale
{
type Output = FixedUnsigned<S>;
fn add(self, rhs: &'b FixedUnsigned<S>) -> FixedUnsigned<S> {
FixedUnsigned::new(FixedUnsigned::<S>::add(&(self.int_value), &(rhs.int_value)))
}
}
impl<S> AddAssign for FixedUnsigned<S>
where S: FixedScale
{
fn add_assign(&mut self, rhs: Self) {
self.int_value = FixedUnsigned::<S>::add(&(self.int_value), &(rhs.int_value))
}
}
impl<S> Sub for FixedUnsigned<S>
where S: FixedScale
{
type Output = Self;
fn sub(self, rhs: FixedUnsigned<S>) -> Self::Output {
Self::new(Self::sub(&(self.int_value), &(rhs.int_value)))
}
}
impl<'a, 'b, S> Sub<&'b FixedUnsigned<S>> for &'a FixedUnsigned<S>
where S: FixedScale
{
type Output = FixedUnsigned<S>;
fn sub(self, rhs: &'b FixedUnsigned<S>) -> FixedUnsigned<S> {
FixedUnsigned::new(FixedUnsigned::<S>::sub(&(self.int_value), &(rhs.int_value)))
}
}
impl<S> SubAssign for FixedUnsigned<S>
where S: FixedScale
{
fn sub_assign(&mut self, rhs: Self) {
self.int_value = FixedUnsigned::<S>::sub(&(self.int_value), &(rhs.int_value))
}
}
impl<S> Mul for FixedUnsigned<S>
where S: FixedScale
{
type Output = Self;
fn mul(self, rhs: FixedUnsigned<S>) -> Self::Output {
Self::new(Self::mul(&(self.int_value), &(rhs.int_value)))
}
}
impl<'a, 'b, S> Mul<&'b FixedUnsigned<S>> for &'a FixedUnsigned<S>
where S: FixedScale
{
type Output = FixedUnsigned<S>;
fn mul(self, rhs: &'b FixedUnsigned<S>) -> FixedUnsigned<S> {
FixedUnsigned::new(FixedUnsigned::<S>::mul(&(self.int_value), &(rhs.int_value)))
}
}
impl<S> MulAssign for FixedUnsigned<S>
where S: FixedScale
{
fn mul_assign(&mut self, rhs: Self) {
self.int_value = FixedUnsigned::<S>::mul(&(self.int_value), &(rhs.int_value))
}
}
impl<S> Div for FixedUnsigned<S>
where S: FixedScale
{
type Output = Self;
fn div(self, rhs: FixedUnsigned<S>) -> Self::Output {
Self::new(Self::div(&(self.int_value), &(rhs.int_value)))
}
}
impl<'a, 'b, S> Div<&'b FixedUnsigned<S>> for &'a FixedUnsigned<S>
where S: FixedScale
{
type Output = FixedUnsigned<S>;
fn div(self, rhs: &'b FixedUnsigned<S>) -> FixedUnsigned<S> {
FixedUnsigned::new(FixedUnsigned::<S>::div(&(self.int_value), &(rhs.int_value)))
}
}
impl<S> DivAssign for FixedUnsigned<S>
where S: FixedScale
{
fn div_assign(&mut self, rhs: Self) {
self.int_value = FixedUnsigned::<S>::div(&(self.int_value), &(rhs.int_value))
}
}
impl<S> PartialEq for FixedUnsigned<S>
where S: FixedScale
{
fn eq(&self, other: &Self) -> bool {
self.int_value.eq(&other.int_value)
}
}
impl<S> Hash for FixedUnsigned<S>
where S: FixedScale
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.int_value.hash(state)
}
}
impl<S> Eq for FixedUnsigned<S>
where S: FixedScale
{
}
impl<S> PartialOrd for FixedUnsigned<S>
where S: FixedScale
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.int_value.partial_cmp(&other.int_value)
}
}
impl<S> Ord for FixedUnsigned<S>
where S: FixedScale
{
fn cmp(&self, other: &Self) -> Ordering {
self.int_value.cmp(&other.int_value)
}
}
impl<S> FromStr for FixedUnsigned<S>
where S: FixedScale
{
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_radix_string(s, 10)
}
}
impl<S> fmt::Debug for FixedUnsigned<S>
where S: FixedScale
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FixedUnsigned({}, scale={})", self.to_radix_string(10, false), S::SCALE)
}
}
impl<S> fmt::Display for FixedUnsigned<S>
where S: FixedScale
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_radix_string(10, false))
}
}
impl<S> From<BigUint> for FixedUnsigned<S>
where S: FixedScale
{
fn from(int_value: BigUint) -> Self {
Self::from_biguint(int_value)
}
}
impl<S: FixedScale> From<u64> for FixedUnsigned<S> {
fn from(x: u64) -> Self {
Self::from_biguint(BigUint::from(x))
}
}
impl<S: FixedScale> From<u32> for FixedUnsigned<S> {
fn from(x: u32) -> Self {
Self::from_biguint(BigUint::from(x))
}
}
impl<S: FixedScale> From<u16> for FixedUnsigned<S> {
fn from(x: u16) -> Self {
Self::from_biguint(BigUint::from(x))
}
}
impl<S: FixedScale> From<u8> for FixedUnsigned<S> {
fn from(x: u8) -> Self {
Self::from_biguint(BigUint::from(x))
}
}
impl<S> Zero for FixedUnsigned<S>
where S: FixedScale
{
fn zero() -> Self {
Self::new(BigUint::zero())
}
fn is_zero(&self) -> bool {
self.int_value.is_zero()
}
}
impl<S> One for FixedUnsigned<S>
where S: FixedScale
{
fn one() -> Self {
Self::from(1u64)
}
}
impl<S> Default for FixedUnsigned<S>
where S: FixedScale
{
fn default() -> Self {
Self::zero()
}
}
impl<S: FixedScale> From<f64> for FixedUnsigned<S> {
fn from(x: f64) -> Self {
Self::from_str(&format!("{:.16}", x)).unwrap()
}
}