use crate::prelude::*;
use derive_more::FromStr;
#[derive(
Clone,
Copy,
Display,
PartialEq,
Eq,
PartialOrd,
Ord,
Default,
Hash,
Debug,
From,
FromStr,
Deref,
derive_more::Mul,
derive_more::Add,
derive_more::Sub,
derive_more::AddAssign,
)]
#[from(rust_decimal::Decimal, u8, i32)]
pub struct Decimal(rust_decimal::Decimal);
impl Decimal {
pub const ZERO: Self = Self(rust_decimal::Decimal::ZERO);
pub const ONE: Self = Self(rust_decimal::Decimal::ONE);
pub const TWO: Self = Self(rust_decimal::Decimal::TWO);
pub const EIGHT: Self = Self(rust_decimal::Decimal::from_parts(8, 0, 0, false, 0));
}
use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
impl TryFrom<Decimal> for f64 {
type Error = crate::Error;
fn try_from(value: Decimal) -> Result<Self> {
value
.0
.to_f64()
.ok_or_else(|| Error::InvalidDecimalToF64Conversion {
value: value.to_string(),
})
}
}
impl TryFrom<f64> for Decimal {
type Error = crate::Error;
fn try_from(value: f64) -> Result<Self> {
rust_decimal::Decimal::from_f64(value)
.ok_or(Error::InvalidDecimalFromF64Conversion { value })
.map(Decimal)
}
}
impl Serialize for Decimal {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
f64::try_from(*self)
.map_err(serde::ser::Error::custom)
.and_then(|f| f.serialize(serializer))
}
}
impl<'de> Deserialize<'de> for Decimal {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
f64::deserialize(deserializer)
.and_then(|f| Decimal::try_from(f).map_err(serde::de::Error::custom))
}
}
#[cfg(test)]
mod tests {
use super::*;
use insta::{assert_ron_snapshot, assert_snapshot};
use test_log::test;
type Sut = Decimal;
#[test]
fn test_display() {
assert_snapshot!(Sut::EIGHT)
}
#[test]
fn test_serde() {
assert_ron_snapshot!(Sut::from(dec!(3.14159265)));
}
#[test]
fn test_decimal_from_f64_nan() {
let result = Sut::try_from(f64::NAN);
assert!(result.is_err());
}
}