1use rust_decimal::Decimal;
2use serde::{de::Error, Deserialize, Deserializer};
3use std::str::FromStr;
4
5static MAX_DIGITS: usize = 19;
7const MAX_PRECISION: usize = 28;
9static ZEROES: &str = "000000000000000000000000000";
11
12fn parse_decimal_digits(dec_str: &str, scale: usize) -> Result<i64, String> {
22 let data_loss_prefix = format!(
24 "Error: '{}' cannot be converted to rust_decimal::Decimal without loss of data:",
25 dec_str,
26 );
27 let num_parts = dec_str
29 .split(".")
30 .map(|s| String::from(s))
31 .collect::<Vec<String>>();
32
33 let integers = num_parts[0].as_str();
34 let fraction = if num_parts.len() == 2 {
35 num_parts[1].trim_end_matches("0")
38 } else {
39 &format!("{ZEROES:.*}", scale)
41 };
42
43 if fraction.len() > scale {
45 return Err(format!(
46 "{} {} fractional digit{} supplied, but scale only permits {}",
47 data_loss_prefix,
48 fraction.len(),
49 if fraction.len() > 1 { "s" } else { "" },
50 scale
51 ));
52 }
53
54 let digits = format!("{integers}{:0<scale$}", fraction);
56 let digits = digits.trim_start_matches("0");
57 let digit_count = digits.len();
58
59 if digit_count == 0 {
61 Ok(0)
62 } else if digit_count > MAX_DIGITS {
63 Err(format!(
64 "{} Too many digits ({}) to fit in an i64 ({})",
65 data_loss_prefix, digit_count, MAX_DIGITS
66 ))
67 } else {
68 Ok(i64::from_str(&format!("{digits}")).unwrap())
69 }
70}
71
72fn dec_str_to_rust_decimal(dec_str: String, scale: usize) -> Result<Decimal, String> {
75 if scale > MAX_PRECISION {
76 return Err(format!(
77 "Scale exceeds the maximum precision allowed: {} > {}",
78 scale, MAX_PRECISION
79 ));
80 }
81
82 if dec_str.is_empty()
84 || dec_str.eq("0")
85 || dec_str.eq("0.0")
86 || dec_str.eq("0.")
87 || dec_str.eq(".0")
88 {
89 return Ok(Decimal::new(0, scale as u32));
90 }
91
92 let digits_i64 = match parse_decimal_digits(&dec_str, scale) {
94 Ok(digits) => digits,
95 Err(err) => panic!("{}", err),
96 };
97
98 Decimal::try_new(digits_i64, scale as u32).or_else(|err| Err(err.to_string()))
99}
100
101fn to_rust_decimal_inner<'de, D>(deserializer: D, scale: u32) -> Result<Decimal, D::Error>
103where
104 D: Deserializer<'de>,
105{
106 match String::deserialize(deserializer) {
107 Ok(dec_str) => {
108 dec_str_to_rust_decimal(dec_str, scale as usize).or_else(|err| Err(Error::custom(err)))
109 }
110 Err(err) => Err(Error::custom(err.to_string())),
111 }
112}
113
114pub fn to_rust_decimal_0dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
116where
117 D: Deserializer<'de>,
118{
119 Ok(to_rust_decimal_0dp(deserializer).ok())
120}
121pub fn to_rust_decimal_1dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
122where
123 D: Deserializer<'de>,
124{
125 Ok(to_rust_decimal_1dp(deserializer).ok())
126}
127pub fn to_rust_decimal_2dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
128where
129 D: Deserializer<'de>,
130{
131 Ok(to_rust_decimal_2dp(deserializer).ok())
132}
133pub fn to_rust_decimal_3dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
134where
135 D: Deserializer<'de>,
136{
137 Ok(to_rust_decimal_3dp(deserializer).ok())
138}
139pub fn to_rust_decimal_4dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
140where
141 D: Deserializer<'de>,
142{
143 Ok(to_rust_decimal_4dp(deserializer).ok())
144}
145pub fn to_rust_decimal_5dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
146where
147 D: Deserializer<'de>,
148{
149 Ok(to_rust_decimal_5dp(deserializer).ok())
150}
151pub fn to_rust_decimal_6dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
152where
153 D: Deserializer<'de>,
154{
155 Ok(to_rust_decimal_6dp(deserializer).ok())
156}
157pub fn to_rust_decimal_7dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
158where
159 D: Deserializer<'de>,
160{
161 Ok(to_rust_decimal_7dp(deserializer).ok())
162}
163pub fn to_rust_decimal_8dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
164where
165 D: Deserializer<'de>,
166{
167 Ok(to_rust_decimal_8dp(deserializer).ok())
168}
169pub fn to_rust_decimal_9dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
170where
171 D: Deserializer<'de>,
172{
173 Ok(to_rust_decimal_9dp(deserializer).ok())
174}
175pub fn to_rust_decimal_10dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
176where
177 D: Deserializer<'de>,
178{
179 Ok(to_rust_decimal_10dp(deserializer).ok())
180}
181pub fn to_rust_decimal_11dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
182where
183 D: Deserializer<'de>,
184{
185 Ok(to_rust_decimal_11dp(deserializer).ok())
186}
187pub fn to_rust_decimal_12dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
188where
189 D: Deserializer<'de>,
190{
191 Ok(to_rust_decimal_12dp(deserializer).ok())
192}
193pub fn to_rust_decimal_13dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
194where
195 D: Deserializer<'de>,
196{
197 Ok(to_rust_decimal_13dp(deserializer).ok())
198}
199pub fn to_rust_decimal_14dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
200where
201 D: Deserializer<'de>,
202{
203 Ok(to_rust_decimal_14dp(deserializer).ok())
204}
205pub fn to_rust_decimal_15dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
206where
207 D: Deserializer<'de>,
208{
209 Ok(to_rust_decimal_15dp(deserializer).ok())
210}
211pub fn to_rust_decimal_16dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
212where
213 D: Deserializer<'de>,
214{
215 Ok(to_rust_decimal_16dp(deserializer).ok())
216}
217pub fn to_rust_decimal_17dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
218where
219 D: Deserializer<'de>,
220{
221 Ok(to_rust_decimal_17dp(deserializer).ok())
222}
223pub fn to_rust_decimal_18dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
224where
225 D: Deserializer<'de>,
226{
227 Ok(to_rust_decimal_18dp(deserializer).ok())
228}
229pub fn to_rust_decimal_19dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
230where
231 D: Deserializer<'de>,
232{
233 Ok(to_rust_decimal_19dp(deserializer).ok())
234}
235pub fn to_rust_decimal_20dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
236where
237 D: Deserializer<'de>,
238{
239 Ok(to_rust_decimal_20dp(deserializer).ok())
240}
241pub fn to_rust_decimal_21dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
242where
243 D: Deserializer<'de>,
244{
245 Ok(to_rust_decimal_21dp(deserializer).ok())
246}
247pub fn to_rust_decimal_22dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
248where
249 D: Deserializer<'de>,
250{
251 Ok(to_rust_decimal_22dp(deserializer).ok())
252}
253pub fn to_rust_decimal_23dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
254where
255 D: Deserializer<'de>,
256{
257 Ok(to_rust_decimal_23dp(deserializer).ok())
258}
259pub fn to_rust_decimal_24dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
260where
261 D: Deserializer<'de>,
262{
263 Ok(to_rust_decimal_24dp(deserializer).ok())
264}
265pub fn to_rust_decimal_25dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
266where
267 D: Deserializer<'de>,
268{
269 Ok(to_rust_decimal_25dp(deserializer).ok())
270}
271pub fn to_rust_decimal_26dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
272where
273 D: Deserializer<'de>,
274{
275 Ok(to_rust_decimal_26dp(deserializer).ok())
276}
277pub fn to_rust_decimal_27dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
278where
279 D: Deserializer<'de>,
280{
281 Ok(to_rust_decimal_27dp(deserializer).ok())
282}
283pub fn to_rust_decimal_28dp_opt<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
284where
285 D: Deserializer<'de>,
286{
287 Ok(to_rust_decimal_28dp(deserializer).ok())
288}
289
290pub fn to_rust_decimal_0dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
292where
293 D: Deserializer<'de>,
294{
295 to_rust_decimal_inner(deserializer, 0)
296}
297pub fn to_rust_decimal_1dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
298where
299 D: Deserializer<'de>,
300{
301 to_rust_decimal_inner(deserializer, 1)
302}
303pub fn to_rust_decimal_2dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
304where
305 D: Deserializer<'de>,
306{
307 to_rust_decimal_inner(deserializer, 2)
308}
309pub fn to_rust_decimal_3dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
310where
311 D: Deserializer<'de>,
312{
313 to_rust_decimal_inner(deserializer, 3)
314}
315pub fn to_rust_decimal_4dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
316where
317 D: Deserializer<'de>,
318{
319 to_rust_decimal_inner(deserializer, 4)
320}
321pub fn to_rust_decimal_5dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
322where
323 D: Deserializer<'de>,
324{
325 to_rust_decimal_inner(deserializer, 5)
326}
327pub fn to_rust_decimal_6dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
328where
329 D: Deserializer<'de>,
330{
331 to_rust_decimal_inner(deserializer, 6)
332}
333pub fn to_rust_decimal_7dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
334where
335 D: Deserializer<'de>,
336{
337 to_rust_decimal_inner(deserializer, 7)
338}
339pub fn to_rust_decimal_8dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
340where
341 D: Deserializer<'de>,
342{
343 to_rust_decimal_inner(deserializer, 8)
344}
345pub fn to_rust_decimal_9dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
346where
347 D: Deserializer<'de>,
348{
349 to_rust_decimal_inner(deserializer, 9)
350}
351pub fn to_rust_decimal_10dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
352where
353 D: Deserializer<'de>,
354{
355 to_rust_decimal_inner(deserializer, 10)
356}
357pub fn to_rust_decimal_11dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
358where
359 D: Deserializer<'de>,
360{
361 to_rust_decimal_inner(deserializer, 11)
362}
363pub fn to_rust_decimal_12dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
364where
365 D: Deserializer<'de>,
366{
367 to_rust_decimal_inner(deserializer, 12)
368}
369pub fn to_rust_decimal_13dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
370where
371 D: Deserializer<'de>,
372{
373 to_rust_decimal_inner(deserializer, 13)
374}
375pub fn to_rust_decimal_14dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
376where
377 D: Deserializer<'de>,
378{
379 to_rust_decimal_inner(deserializer, 14)
380}
381pub fn to_rust_decimal_15dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
382where
383 D: Deserializer<'de>,
384{
385 to_rust_decimal_inner(deserializer, 15)
386}
387pub fn to_rust_decimal_16dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
388where
389 D: Deserializer<'de>,
390{
391 to_rust_decimal_inner(deserializer, 16)
392}
393pub fn to_rust_decimal_17dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
394where
395 D: Deserializer<'de>,
396{
397 to_rust_decimal_inner(deserializer, 17)
398}
399pub fn to_rust_decimal_18dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
400where
401 D: Deserializer<'de>,
402{
403 to_rust_decimal_inner(deserializer, 18)
404}
405pub fn to_rust_decimal_19dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
406where
407 D: Deserializer<'de>,
408{
409 to_rust_decimal_inner(deserializer, 19)
410}
411pub fn to_rust_decimal_20dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
412where
413 D: Deserializer<'de>,
414{
415 to_rust_decimal_inner(deserializer, 20)
416}
417pub fn to_rust_decimal_21dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
418where
419 D: Deserializer<'de>,
420{
421 to_rust_decimal_inner(deserializer, 21)
422}
423pub fn to_rust_decimal_22dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
424where
425 D: Deserializer<'de>,
426{
427 to_rust_decimal_inner(deserializer, 22)
428}
429pub fn to_rust_decimal_23dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
430where
431 D: Deserializer<'de>,
432{
433 to_rust_decimal_inner(deserializer, 23)
434}
435pub fn to_rust_decimal_24dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
436where
437 D: Deserializer<'de>,
438{
439 to_rust_decimal_inner(deserializer, 24)
440}
441pub fn to_rust_decimal_25dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
442where
443 D: Deserializer<'de>,
444{
445 to_rust_decimal_inner(deserializer, 25)
446}
447pub fn to_rust_decimal_26dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
448where
449 D: Deserializer<'de>,
450{
451 to_rust_decimal_inner(deserializer, 26)
452}
453pub fn to_rust_decimal_27dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
454where
455 D: Deserializer<'de>,
456{
457 to_rust_decimal_inner(deserializer, 27)
458}
459pub fn to_rust_decimal_28dp<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
460where
461 D: Deserializer<'de>,
462{
463 to_rust_decimal_inner(deserializer, 28)
464}
465
466#[cfg(test)]
468mod parser_tests;
469#[cfg(test)]
470mod unit_tests;