use crate::fpdec_inner::FpdecInner;
use crate::ParseError;
use crate::static_prec_fpdec::StaticPrecFpdec;
use int_div_cum_error::{Rounding, checked_divide};
use num_traits::{Num, cast::FromPrimitive, float::Float};
use std::fmt;
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default, Debug)]
pub struct OobPrecFpdec<I>(I);
impl<I> OobPrecFpdec<I>
where I: FpdecInner
{
crate::none_prec_common::define_none_prec_common!();
pub fn checked_mul<J>(
self,
rhs: OobPrecFpdec<J>,
diff_precision: i32, ) -> Option<OobPrecFpdec<I>>
where J: FpdecInner
{
self.checked_mul_ext(rhs, diff_precision, Rounding::Round, None)
}
pub fn checked_mul_ext<J>(
self,
rhs: OobPrecFpdec<J>,
diff_precision: i32, rounding: Rounding,
cum_error: Option<&mut I>,
) -> Option<OobPrecFpdec<I>>
where J: FpdecInner
{
self.0.checked_mul_ext(I::from(rhs.0)?, diff_precision, rounding, cum_error)
.map(Self)
}
pub fn checked_div<J>(
self,
rhs: OobPrecFpdec<J>,
diff_precision: i32, ) -> Option<OobPrecFpdec<I>>
where J: FpdecInner
{
self.checked_div_ext(rhs, diff_precision, Rounding::Round, None)
}
pub fn checked_div_ext<J>(
self,
rhs: OobPrecFpdec<J>,
diff_precision: i32, rounding: Rounding,
cum_error: Option<&mut I>,
) -> Option<OobPrecFpdec<I>>
where J: FpdecInner
{
self.0.checked_div_ext(I::from(rhs.0)?, diff_precision, rounding, cum_error)
.map(Self)
}
pub fn shrink(self, reduce_precision: i32) -> Self {
self.shrink_with_rounding(reduce_precision, Rounding::Round)
}
pub fn shrink_with_rounding(
self,
reduce_precision: i32,
rounding: Rounding,
) -> Self {
Self(self.0.shrink_with_rounding(reduce_precision, rounding))
}
pub fn try_from_str(s: &str, precision: i32) -> Result<Self, ParseError>
where ParseError: From<<I as Num>::FromStrRadixErr>
{
I::try_from_str(s, precision).map(Self)
}
pub fn into_float<F>(self, precision: i32) -> F
where F: Float
{
let base = F::from(10.0).unwrap();
F::from(self.0).unwrap() / base.powi(precision)
}
}
macro_rules! convert_from_int {
($from_int_type:ty) => {
impl<I> TryFrom<($from_int_type, i32)> for OobPrecFpdec<I>
where I: FpdecInner
{
type Error = ParseError;
fn try_from(i: ($from_int_type, i32)) -> Result<Self, Self::Error> {
let i2 = <$from_int_type>::checked_from_int(i.0, i.1)?;
I::from(i2).ok_or(ParseError::Overflow).map(Self)
}
}
}
}
convert_from_int!(i8);
convert_from_int!(i16);
convert_from_int!(i32);
convert_from_int!(i64);
convert_from_int!(i128);
macro_rules! convert_from_float {
($float_type:ty, $from_fn:ident, $to_fn:ident) => {
impl<I> TryFrom<($float_type, i32)> for OobPrecFpdec<I>
where I: FromPrimitive + FpdecInner
{
type Error = ParseError;
fn try_from(f: ($float_type, i32)) -> Result<Self, Self::Error> {
let base: $float_type = 10.0;
let inner_f = f.0 * base.powi(f.1) as $float_type;
I::$from_fn(inner_f.round())
.map(Self)
.ok_or(ParseError::Overflow)
}
}
}
}
convert_from_float!(f32, from_f32, to_f32);
convert_from_float!(f64, from_f64, to_f64);
impl<I> OobPrecFpdec<I>
where I: FpdecInner
{
pub fn checked_mul_static<J, const Q: i32>(self, rhs: StaticPrecFpdec<J, Q>)
-> Option<Self>
where J: FpdecInner
{
self.checked_mul_static_ext(rhs, Rounding::Round, None)
}
pub fn checked_mul_static_ext<J, const Q: i32>(
self,
rhs: StaticPrecFpdec<J, Q>,
rounding: Rounding,
cum_error: Option<&mut I>,
) -> Option<Self>
where J: FpdecInner
{
self.0.checked_mul_ext(I::from(rhs.0)?, Q, rounding, cum_error)
.map(Self)
}
pub fn checked_div_static<J, const Q: i32>(self, rhs: StaticPrecFpdec<J, Q>)
-> Option<Self>
where J: FpdecInner
{
self.checked_div_static_ext(rhs, Rounding::Round, None)
}
pub fn checked_div_static_ext<J, const Q: i32>(
self,
rhs: StaticPrecFpdec<J, Q>,
rounding: Rounding,
cum_error: Option<&mut I>,
) -> Option<Self>
where J: FpdecInner
{
self.0.checked_div_ext(I::from(rhs.0)?, -Q, rounding, cum_error)
.map(Self)
}
}
impl<I> std::ops::Neg for OobPrecFpdec<I>
where I: FpdecInner
{
type Output = Self;
fn neg(self) -> Self::Output {
Self(-self.0)
}
}
impl<I> std::ops::Add for OobPrecFpdec<I>
where I: FpdecInner
{
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl<I> std::ops::Sub for OobPrecFpdec<I>
where I: FpdecInner
{
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}
impl<I> std::ops::AddAssign for OobPrecFpdec<I>
where I: FpdecInner
{
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl<I> std::ops::SubAssign for OobPrecFpdec<I>
where I: FpdecInner
{
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default, Debug)]
pub struct OobFmt<I>(pub OobPrecFpdec<I>, pub i32);
impl<I> fmt::Display for OobFmt<I>
where I: FpdecInner + fmt::Display
{
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let precision = self.1;
self.0.0.display_fmt(precision, f)
}
}