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