1use crate::decimal::{self, Decimal};
4use paft_decimal::{DecimalConstraintError, NonNegativeDecimal};
5use serde::{Deserialize, Serialize};
6use std::fmt;
7use std::hash::{Hash, Hasher};
8
9#[cfg(feature = "dataframe")]
10use df_derive_macros::ToDataFrame;
11
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19#[serde(transparent)]
20#[cfg_attr(feature = "dataframe", derive(ToDataFrame))]
21pub struct QuantityAmount {
22 #[cfg_attr(feature = "dataframe", df_derive(decimal(precision = 38, scale = 10)))]
23 amount: NonNegativeDecimal,
24}
25
26impl QuantityAmount {
27 #[must_use]
29 pub const fn new(amount: NonNegativeDecimal) -> Self {
30 Self { amount }
31 }
32
33 pub fn from_decimal(amount: Decimal) -> Result<Self, DecimalConstraintError> {
39 Ok(Self::new(NonNegativeDecimal::new(amount)?))
40 }
41
42 #[must_use]
44 pub const fn as_non_negative_decimal(&self) -> &NonNegativeDecimal {
45 &self.amount
46 }
47
48 #[must_use]
50 pub const fn as_decimal(&self) -> &Decimal {
51 self.amount.as_decimal()
52 }
53
54 #[must_use]
56 #[cfg(not(feature = "bigdecimal"))]
57 pub const fn into_inner(self) -> NonNegativeDecimal {
58 self.amount
59 }
60
61 #[must_use]
63 #[cfg(feature = "bigdecimal")]
64 pub fn into_inner(self) -> NonNegativeDecimal {
65 self.amount
66 }
67}
68
69impl AsRef<NonNegativeDecimal> for QuantityAmount {
70 fn as_ref(&self) -> &NonNegativeDecimal {
71 self.as_non_negative_decimal()
72 }
73}
74
75#[cfg(feature = "dataframe")]
76impl paft_utils::dataframe::Decimal128Encode for QuantityAmount {
77 fn try_to_i128_mantissa(&self, target_scale: u32) -> Option<i128> {
78 paft_utils::dataframe::Decimal128Encode::try_to_i128_mantissa(
79 self.as_non_negative_decimal(),
80 target_scale,
81 )
82 }
83}
84
85impl TryFrom<Decimal> for QuantityAmount {
86 type Error = DecimalConstraintError;
87
88 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
89 Self::from_decimal(value)
90 }
91}
92
93impl From<NonNegativeDecimal> for QuantityAmount {
94 fn from(value: NonNegativeDecimal) -> Self {
95 Self::new(value)
96 }
97}
98
99impl From<QuantityAmount> for NonNegativeDecimal {
100 fn from(value: QuantityAmount) -> Self {
101 value.into_inner()
102 }
103}
104
105impl Hash for QuantityAmount {
106 fn hash<H: Hasher>(&self, state: &mut H) {
107 decimal::to_canonical_string(self.as_decimal()).hash(state);
108 }
109}
110
111impl fmt::Display for QuantityAmount {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 f.write_str(&decimal::to_canonical_string(self.as_decimal()))
114 }
115}