Skip to main content

teaql_tool_std/
decimal.rs

1use rust_decimal::Decimal;
2use rust_decimal::RoundingStrategy;
3use std::str::FromStr;
4use teaql_tool_core::{MustPurpose, Result, TeaQLToolError};
5
6pub struct DecimalTool;
7
8impl DecimalTool {
9    pub fn new() -> Self {
10        Self
11    }
12
13    pub fn of(&self, s: &str) -> Result<MustPurpose<Decimal>> {
14        Decimal::from_str(s)
15            .map(MustPurpose::new)
16            .map_err(|e| TeaQLToolError::ParseError(e.to_string()))
17    }
18
19    pub fn zero(&self) -> MustPurpose<Decimal> {
20        MustPurpose::new(Decimal::ZERO)
21    }
22
23    pub fn one(&self) -> MustPurpose<Decimal> {
24        MustPurpose::new(Decimal::ONE)
25    }
26
27    pub fn add(&self, a: Decimal, b: Decimal) -> MustPurpose<Decimal> {
28        MustPurpose::new(a + b)
29    }
30
31    pub fn sub(&self, a: Decimal, b: Decimal) -> MustPurpose<Decimal> {
32        MustPurpose::new(a - b)
33    }
34
35    pub fn mul(&self, a: Decimal, b: Decimal) -> MustPurpose<Decimal> {
36        MustPurpose::new(a * b)
37    }
38
39    pub fn div(&self, a: Decimal, b: Decimal) -> Result<MustPurpose<Decimal>> {
40        if b.is_zero() {
41            Err(TeaQLToolError::InvalidArgument(
42                "Division by zero".to_string(),
43            ))
44        } else {
45            Ok(MustPurpose::new(a / b))
46        }
47    }
48
49    pub fn round(&self, a: Decimal, dp: u32) -> MustPurpose<Decimal> {
50        MustPurpose::new(a.round_dp_with_strategy(dp, RoundingStrategy::MidpointNearestEven))
51    }
52
53    pub fn ceil(&self, a: Decimal) -> MustPurpose<Decimal> {
54        MustPurpose::new(a.ceil())
55    }
56
57    pub fn floor(&self, a: Decimal) -> MustPurpose<Decimal> {
58        MustPurpose::new(a.floor())
59    }
60
61    pub fn abs(&self, a: Decimal) -> MustPurpose<Decimal> {
62        MustPurpose::new(a.abs())
63    }
64
65    pub fn min(&self, a: Decimal, b: Decimal) -> MustPurpose<Decimal> {
66        MustPurpose::new(a.min(b))
67    }
68
69    pub fn max(&self, a: Decimal, b: Decimal) -> MustPurpose<Decimal> {
70        MustPurpose::new(a.max(b))
71    }
72
73    pub fn percent(&self, amount: Decimal, pct: Decimal) -> MustPurpose<Decimal> {
74        MustPurpose::new((amount * pct) / Decimal::from(100))
75    }
76
77    pub fn ratio(&self, part: Decimal, total: Decimal) -> Result<MustPurpose<Decimal>> {
78        self.div(part, total)
79    }
80}
81
82impl Default for DecimalTool {
83    fn default() -> Self {
84        Self::new()
85    }
86}