reifydb_type/value/decimal/
mod.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the MIT, see license.md file
3
4use 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, OwnedFragment, 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(OwnedFragment::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
220// Serde implementation for string-based serialization
221// This works with both JSON and binary formats (bincode, rmp, etc.)
222impl 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 bincode::{
260		config::standard,
261		serde::{decode_from_slice, encode_to_vec},
262	};
263
264	use super::*;
265
266	#[test]
267	fn test_new_decimal_valid() {
268		let bd = BigDecimalInner::from_str("123.45").unwrap();
269		let decimal = Decimal::new(bd);
270		assert_eq!(decimal.to_string(), "123.45");
271	}
272
273	#[test]
274	fn test_from_str() {
275		let decimal = Decimal::from_str("123.45").unwrap();
276		assert_eq!(decimal.to_string(), "123.45");
277	}
278
279	#[test]
280	fn test_comparison() {
281		let d1 = Decimal::from_str("123.45").unwrap();
282		let d2 = Decimal::from_str("123.46").unwrap();
283		let d3 = Decimal::from_str("123.45").unwrap();
284
285		assert!(d1 < d2);
286		assert_eq!(d1, d3);
287	}
288
289	#[test]
290	fn test_display() {
291		let decimal = Decimal::from_str("123.45").unwrap();
292		assert_eq!(format!("{}", decimal), "123.45");
293	}
294
295	#[test]
296	fn test_serde_json() {
297		let decimal = Decimal::from_str("123.456789").unwrap();
298		let json = serde_json::to_string(&decimal).unwrap();
299		assert_eq!(json, "\"123.456789\"");
300
301		let deserialized: Decimal = serde_json::from_str(&json).unwrap();
302		assert_eq!(deserialized, decimal);
303	}
304
305	#[test]
306	fn test_serde_json_negative() {
307		let decimal = Decimal::from_str("-987.654321").unwrap();
308		let json = serde_json::to_string(&decimal).unwrap();
309		assert_eq!(json, "\"-987.654321\"");
310
311		let deserialized: Decimal = serde_json::from_str(&json).unwrap();
312		assert_eq!(deserialized, decimal);
313	}
314
315	#[test]
316	fn test_serde_json_zero() {
317		let decimal = Decimal::zero();
318		let json = serde_json::to_string(&decimal).unwrap();
319		assert_eq!(json, "\"0\"");
320
321		let deserialized: Decimal = serde_json::from_str(&json).unwrap();
322		assert_eq!(deserialized, decimal);
323	}
324
325	#[test]
326	fn test_serde_json_high_precision() {
327		let decimal = Decimal::from_str("123456789.123456789123456789").unwrap();
328		let json = serde_json::to_string(&decimal).unwrap();
329
330		let deserialized: Decimal = serde_json::from_str(&json).unwrap();
331		assert_eq!(deserialized, decimal);
332	}
333
334	#[test]
335	fn test_serde_bincode() {
336		let decimal = Decimal::from_str("123.456789").unwrap();
337		let encoded = encode_to_vec(&decimal, standard()).unwrap();
338
339		let (decoded, _): (Decimal, usize) = decode_from_slice(&encoded, standard()).unwrap();
340		assert_eq!(decoded, decimal);
341	}
342
343	#[test]
344	fn test_serde_bincode_negative() {
345		let decimal = Decimal::from_str("-987.654321").unwrap();
346		let encoded = encode_to_vec(&decimal, standard()).unwrap();
347
348		let (decoded, _): (Decimal, usize) = decode_from_slice(&encoded, standard()).unwrap();
349		assert_eq!(decoded, decimal);
350	}
351
352	#[test]
353	fn test_serde_bincode_zero() {
354		let decimal = Decimal::zero();
355		let encoded = encode_to_vec(&decimal, standard()).unwrap();
356
357		let (decoded, _): (Decimal, usize) = decode_from_slice(&encoded, standard()).unwrap();
358		assert_eq!(decoded, decimal);
359	}
360
361	#[test]
362	fn test_serde_bincode_high_precision() {
363		let decimal = Decimal::from_str("123456789.123456789123456789").unwrap();
364		let encoded = encode_to_vec(&decimal, standard()).unwrap();
365
366		let (decoded, _): (Decimal, usize) = decode_from_slice(&encoded, standard()).unwrap();
367		assert_eq!(decoded, decimal);
368	}
369
370	#[test]
371	fn test_serde_bincode_large_number() {
372		let decimal = Decimal::from_str("999999999999999999999999999999.999999999999999999999999").unwrap();
373		let encoded = encode_to_vec(&decimal, standard()).unwrap();
374
375		let (decoded, _): (Decimal, usize) = decode_from_slice(&encoded, standard()).unwrap();
376		assert_eq!(decoded, decimal);
377	}
378}