reifydb_type/value/decimal/
mod.rs1use std::{
5 cmp::Ordering,
6 fmt::{Display, Formatter},
7 ops::Deref,
8 str::FromStr,
9};
10
11use bigdecimal::{BigDecimal as BigDecimalInner, FromPrimitive};
12use num_traits::{One, Zero};
13use serde::{
14 Deserialize, Deserializer, Serialize, Serializer,
15 de::{self, Visitor},
16};
17
18use super::{int::Int, uint::Uint};
19use crate::{Error, Fragment, Type, error};
20
21mod parse;
22
23pub use parse::parse_decimal;
24
25use crate::error::diagnostic::number::invalid_number_format;
26
27#[repr(transparent)]
28#[derive(Clone, Debug)]
29pub struct Decimal(pub BigDecimalInner);
30
31impl Decimal {
32 pub fn zero() -> Self {
33 Self(BigDecimalInner::zero())
34 }
35
36 pub fn one() -> Self {
37 Self(BigDecimalInner::one())
38 }
39}
40
41impl Deref for Decimal {
42 type Target = BigDecimalInner;
43
44 fn deref(&self) -> &Self::Target {
45 &self.0
46 }
47}
48
49impl Decimal {
50 pub fn new(value: BigDecimalInner) -> Self {
51 Self(value)
52 }
53
54 pub fn from_bigdecimal(value: BigDecimalInner) -> Self {
55 Self(value)
56 }
57
58 pub fn with_scale(value: BigDecimalInner, scale: i64) -> Self {
59 Self(value.with_scale(scale))
60 }
61
62 pub fn from_i64(value: i64) -> Self {
63 Self(BigDecimalInner::from(value))
64 }
65
66 pub fn inner(&self) -> &BigDecimalInner {
67 &self.0
68 }
69
70 pub fn to_bigdecimal(self) -> BigDecimalInner {
71 self.0
72 }
73
74 pub fn negate(self) -> Self {
75 Self(-self.0)
76 }
77}
78
79impl PartialEq for Decimal {
80 fn eq(&self, other: &Self) -> bool {
81 self.0 == other.0
82 }
83}
84
85impl Eq for Decimal {}
86
87impl PartialOrd for Decimal {
88 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
89 Some(self.cmp(other))
90 }
91}
92
93impl Ord for Decimal {
94 fn cmp(&self, other: &Self) -> Ordering {
95 self.0.cmp(&other.0)
96 }
97}
98
99impl Display for Decimal {
100 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
101 self.0.fmt(f)
102 }
103}
104
105impl std::hash::Hash for Decimal {
106 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
107 self.0.to_string().hash(state);
108 }
109}
110
111impl FromStr for Decimal {
112 type Err = Error;
113
114 fn from_str(s: &str) -> Result<Self, Self::Err> {
115 let big_decimal = BigDecimalInner::from_str(s)
116 .map_err(|_| error!(invalid_number_format(Fragment::None, Type::Decimal)))?;
117
118 Ok(Self(big_decimal))
119 }
120}
121
122impl From<i64> for Decimal {
123 fn from(value: i64) -> Self {
124 Self(BigDecimalInner::from(value))
125 }
126}
127
128impl From<i8> for Decimal {
129 fn from(value: i8) -> Self {
130 Self::from(value as i64)
131 }
132}
133
134impl From<i16> for Decimal {
135 fn from(value: i16) -> Self {
136 Self::from(value as i64)
137 }
138}
139
140impl From<i32> for Decimal {
141 fn from(value: i32) -> Self {
142 Self::from(value as i64)
143 }
144}
145
146impl From<i128> for Decimal {
147 fn from(value: i128) -> Self {
148 Self(BigDecimalInner::from(value))
149 }
150}
151
152impl From<u8> for Decimal {
153 fn from(value: u8) -> Self {
154 Self::from(value as i64)
155 }
156}
157
158impl From<u16> for Decimal {
159 fn from(value: u16) -> Self {
160 Self::from(value as i64)
161 }
162}
163
164impl From<u32> for Decimal {
165 fn from(value: u32) -> Self {
166 Self::from(value as i64)
167 }
168}
169
170impl From<u64> for Decimal {
171 fn from(value: u64) -> Self {
172 Self(BigDecimalInner::from(value))
173 }
174}
175
176impl From<u128> for Decimal {
177 fn from(value: u128) -> Self {
178 Self(BigDecimalInner::from(value))
179 }
180}
181
182impl From<f32> for Decimal {
183 fn from(value: f32) -> Self {
184 let inner = BigDecimalInner::from_f32(value).unwrap_or_else(|| BigDecimalInner::from(0));
185 Self(inner)
186 }
187}
188
189impl From<f64> for Decimal {
190 fn from(value: f64) -> Self {
191 let inner = BigDecimalInner::from_f64(value).unwrap_or_else(|| BigDecimalInner::from(0));
192 Self(inner)
193 }
194}
195
196impl From<BigDecimalInner> for Decimal {
197 fn from(value: BigDecimalInner) -> Self {
198 Self(value)
199 }
200}
201
202impl From<Int> for Decimal {
203 fn from(value: Int) -> Self {
204 Self(BigDecimalInner::from_bigint(value.0, 0))
205 }
206}
207
208impl From<Uint> for Decimal {
209 fn from(value: Uint) -> Self {
210 Self(BigDecimalInner::from_bigint(value.0, 0))
211 }
212}
213
214impl Default for Decimal {
215 fn default() -> Self {
216 Self::zero()
217 }
218}
219
220impl Serialize for Decimal {
223 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
224 where
225 S: Serializer,
226 {
227 serializer.serialize_str(&self.0.to_string())
228 }
229}
230
231struct DecimalVisitor;
232
233impl<'de> Visitor<'de> for DecimalVisitor {
234 type Value = Decimal;
235
236 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
237 formatter.write_str("a decimal number as a string")
238 }
239
240 fn visit_str<E>(self, value: &str) -> Result<Decimal, E>
241 where
242 E: de::Error,
243 {
244 BigDecimalInner::from_str(value).map(Decimal).map_err(|e| E::custom(format!("invalid decimal: {}", e)))
245 }
246}
247
248impl<'de> Deserialize<'de> for Decimal {
249 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
250 where
251 D: Deserializer<'de>,
252 {
253 deserializer.deserialize_str(DecimalVisitor)
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260
261 #[test]
262 fn test_new_decimal_valid() {
263 let bd = BigDecimalInner::from_str("123.45").unwrap();
264 let decimal = Decimal::new(bd);
265 assert_eq!(decimal.to_string(), "123.45");
266 }
267
268 #[test]
269 fn test_from_str() {
270 let decimal = Decimal::from_str("123.45").unwrap();
271 assert_eq!(decimal.to_string(), "123.45");
272 }
273
274 #[test]
275 fn test_comparison() {
276 let d1 = Decimal::from_str("123.45").unwrap();
277 let d2 = Decimal::from_str("123.46").unwrap();
278 let d3 = Decimal::from_str("123.45").unwrap();
279
280 assert!(d1 < d2);
281 assert_eq!(d1, d3);
282 }
283
284 #[test]
285 fn test_display() {
286 let decimal = Decimal::from_str("123.45").unwrap();
287 assert_eq!(format!("{}", decimal), "123.45");
288 }
289
290 #[test]
291 fn test_serde_json() {
292 let decimal = Decimal::from_str("123.456789").unwrap();
293 let json = serde_json::to_string(&decimal).unwrap();
294 assert_eq!(json, "\"123.456789\"");
295
296 let deserialized: Decimal = serde_json::from_str(&json).unwrap();
297 assert_eq!(deserialized, decimal);
298 }
299
300 #[test]
301 fn test_serde_json_negative() {
302 let decimal = Decimal::from_str("-987.654321").unwrap();
303 let json = serde_json::to_string(&decimal).unwrap();
304 assert_eq!(json, "\"-987.654321\"");
305
306 let deserialized: Decimal = serde_json::from_str(&json).unwrap();
307 assert_eq!(deserialized, decimal);
308 }
309
310 #[test]
311 fn test_serde_json_zero() {
312 let decimal = Decimal::zero();
313 let json = serde_json::to_string(&decimal).unwrap();
314 assert_eq!(json, "\"0\"");
315
316 let deserialized: Decimal = serde_json::from_str(&json).unwrap();
317 assert_eq!(deserialized, decimal);
318 }
319
320 #[test]
321 fn test_serde_json_high_precision() {
322 let decimal = Decimal::from_str("123456789.123456789123456789").unwrap();
323 let json = serde_json::to_string(&decimal).unwrap();
324
325 let deserialized: Decimal = serde_json::from_str(&json).unwrap();
326 assert_eq!(deserialized, decimal);
327 }
328
329 #[test]
330 fn test_serde_postcard() {
331 let decimal = Decimal::from_str("123.456789").unwrap();
332 let encoded = postcard::to_stdvec(&decimal).unwrap();
333
334 let decoded: Decimal = postcard::from_bytes(&encoded).unwrap();
335 assert_eq!(decoded, decimal);
336 }
337
338 #[test]
339 fn test_serde_postcard_negative() {
340 let decimal = Decimal::from_str("-987.654321").unwrap();
341 let encoded = postcard::to_stdvec(&decimal).unwrap();
342
343 let decoded: Decimal = postcard::from_bytes(&encoded).unwrap();
344 assert_eq!(decoded, decimal);
345 }
346
347 #[test]
348 fn test_serde_postcard_zero() {
349 let decimal = Decimal::zero();
350 let encoded = postcard::to_stdvec(&decimal).unwrap();
351
352 let decoded: Decimal = postcard::from_bytes(&encoded).unwrap();
353 assert_eq!(decoded, decimal);
354 }
355
356 #[test]
357 fn test_serde_postcard_high_precision() {
358 let decimal = Decimal::from_str("123456789.123456789123456789").unwrap();
359 let encoded = postcard::to_stdvec(&decimal).unwrap();
360
361 let decoded: Decimal = postcard::from_bytes(&encoded).unwrap();
362 assert_eq!(decoded, decimal);
363 }
364
365 #[test]
366 fn test_serde_postcard_large_number() {
367 let decimal = Decimal::from_str("999999999999999999999999999999.999999999999999999999999").unwrap();
368 let encoded = postcard::to_stdvec(&decimal).unwrap();
369
370 let decoded: Decimal = postcard::from_bytes(&encoded).unwrap();
371 assert_eq!(decoded, decimal);
372 }
373}