bigdecimal/
impl_fmt.rs

1//! Implementation of std::fmt traits & other stringification functions
2//!
3
4use crate::*;
5use rounding::{NonDigitRoundingData, InsigData};
6use stdlib::fmt::Write;
7use stdlib::num::NonZeroUsize;
8
9
10// const EXPONENTIAL_FORMAT_LEADING_ZERO_THRESHOLD: usize = ${RUST_BIGDECIMAL_FMT_EXPONENTIAL_LOWER_THRESHOLD} or 5;
11// const EXPONENTIAL_FORMAT_TRAILING_ZERO_THRESHOLD: usize = ${RUST_BIGDECIMAL_FMT_EXPONENTIAL_UPPER_THRESHOLD} or 15;
12// const FMT_MAX_INTEGER_PADDING: usize = = ${RUST_BIGDECIMAL_FMT_MAX_INTEGER_PADDING} or  1000;
13include!(concat!(env!("OUT_DIR"), "/exponential_format_threshold.rs"));
14
15
16impl fmt::Display for BigDecimal {
17    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
18        dynamically_format_decimal(
19            self.to_ref(),
20            f,
21            EXPONENTIAL_FORMAT_LEADING_ZERO_THRESHOLD,
22            EXPONENTIAL_FORMAT_TRAILING_ZERO_THRESHOLD,
23        )
24    }
25}
26
27impl fmt::Display for BigDecimalRef<'_> {
28    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29        dynamically_format_decimal(
30            *self,
31            f,
32            EXPONENTIAL_FORMAT_LEADING_ZERO_THRESHOLD,
33            EXPONENTIAL_FORMAT_TRAILING_ZERO_THRESHOLD,
34        )
35    }
36}
37
38
39impl fmt::LowerExp for BigDecimal {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        fmt::LowerExp::fmt(&self.to_ref(), f)
42    }
43}
44
45impl fmt::LowerExp for BigDecimalRef<'_> {
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        let abs_int = self.digits.to_str_radix(10);
48        format_exponential(*self, f, abs_int, "e")
49    }
50}
51
52
53impl fmt::UpperExp for BigDecimal {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        fmt::UpperExp::fmt(&self.to_ref(), f)
56    }
57}
58
59impl fmt::UpperExp for BigDecimalRef<'_> {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        let abs_int = self.digits.to_str_radix(10);
62        format_exponential(*self, f, abs_int, "E")
63    }
64}
65
66
67impl fmt::Debug for BigDecimal {
68    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69        if f.alternate() {
70            write!(f, "BigDecimal(\"{}e{:}\")", self.int_val, -self.scale)
71        } else {
72            write!(f,
73                "BigDecimal(sign={:?}, scale={}, digits={:?})",
74                self.sign(), self.scale, self.int_val.magnitude().to_u64_digits()
75            )
76        }
77    }
78}
79
80
81fn dynamically_format_decimal(
82    this: BigDecimalRef,
83    f: &mut fmt::Formatter,
84    leading_zero_threshold: usize,
85    trailing_zero_threshold: usize,
86) -> fmt::Result {
87    // Acquire the absolute integer as a decimal string
88    let abs_int = this.digits.to_str_radix(10);
89
90    // number of zeros between most significant digit and decimal point
91    let leading_zero_count = this.scale
92                                 .to_u64()
93                                 .and_then(|scale| scale.checked_sub(abs_int.len() as u64))
94                                 .unwrap_or(0);
95
96    // number of zeros between least significant digit and decimal point
97    let trailing_zero_count = this.scale
98                                  .checked_neg()
99                                  .and_then(|d| d.to_u64());
100
101    // this ignores scientific-formatting if precision is requested
102    let trailing_zeros = f.precision().map(|_| 0)
103                          .or(trailing_zero_count)
104                          .unwrap_or(0);
105
106    let leading_zero_threshold = leading_zero_threshold as u64;
107    let trailing_zero_threshold = trailing_zero_threshold as u64;
108
109    // use exponential form if decimal point is outside
110    // the upper and lower thresholds of the decimal,
111    // and precision was not requested
112    if f.precision().is_none() && leading_zero_threshold < leading_zero_count {
113        format_exponential(this, f, abs_int, "E")
114    } else if trailing_zero_threshold < trailing_zeros {
115        // non-scientific notation
116        format_dotless_exponential(f, abs_int, this.sign, this.scale, "e")
117    } else {
118        format_full_scale(this, f, abs_int)
119    }
120}
121
122
123pub(crate) struct FullScaleFormatter<'a>(pub BigDecimalRef<'a>);
124
125impl fmt::Display for FullScaleFormatter<'_> {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        let n = self.0;
128        let non_negative = matches!(n.sign, Sign::Plus | Sign::NoSign);
129
130        let mut digits = n.digits.to_string();
131
132        if n.scale <= 0 {
133            digits.extend(stdlib::iter::repeat('0').take(n.scale.neg() as usize));
134        } else if n.scale < digits.len() as i64 {
135            digits.insert(digits.len() - n.scale as usize, '.');
136        } else {
137            let mut digit_vec = digits.into_bytes();
138
139            let dest_str_size = n.scale as usize + 2;
140            let digit_count = digit_vec.len();
141            let leading_char_idx = dest_str_size - digit_count;
142
143            digit_vec.resize(dest_str_size, b'0');
144            digit_vec.copy_within(0..digit_count, leading_char_idx);
145            fill_slice(&mut digit_vec[..digit_count.min(leading_char_idx)], b'0');
146
147            digit_vec[1] = b'.';
148            digits = String::from_utf8(digit_vec).unwrap();
149        }
150
151        f.pad_integral(non_negative, "", &digits)
152    }
153}
154
155
156fn format_full_scale(
157    this: BigDecimalRef,
158    f: &mut fmt::Formatter,
159    abs_int: String,
160) -> fmt::Result {
161    use stdlib::cmp::Ordering::*;
162
163    let mut digits = abs_int.into_bytes();
164    let mut exp = 0;
165    let non_negative = matches!(this.sign, Sign::Plus | Sign::NoSign);
166
167    debug_assert_ne!(digits.len(), 0);
168
169    let rounder = NonDigitRoundingData::default_with_sign(this.sign);
170
171    if this.scale <= 0 {
172        exp = (this.scale as i128).neg();
173        // format an integer value by adding trailing zeros to the right
174        zero_right_pad_integer_ascii_digits(&mut digits, &mut exp, f.precision());
175    } else {
176        let scale = this.scale as u64;
177
178        // std::fmt 'precision' has same meaning as bigdecimal 'scale'
179        //
180        // interpret 'no-precision' to mean the same as matching the scale
181        // of the deicmal (i.e. no padding or rounding)
182        let target_scale = f.precision().and_then(|prec| prec.to_u64()).unwrap_or(scale);
183
184        if scale < digits.len() as u64 {
185            // format both integer and fractional digits (always 'trim' to precision)
186            format_ascii_digits_with_integer_and_fraction(&mut digits, scale, target_scale, rounder);
187        } else {
188            // format only fractional digits
189            format_ascii_digits_no_integer(&mut digits, scale, target_scale, rounder);
190        }
191    }
192
193    // move digits back into String form
194    let mut buf = String::from_utf8(digits).unwrap();
195
196    // add exp part to buffer (if not zero)
197    if exp != 0 {
198        write!(buf, "e{:+}", exp)?;
199    }
200
201    // write buffer to formatter
202    f.pad_integral(non_negative, "", &buf)
203}
204
205/// Fill appropriate number of zeros and decimal point into Vec of (ascii/utf-8) digits
206///
207/// Exponent is set to zero if zeros were added
208///
209fn zero_right_pad_integer_ascii_digits(
210    digits: &mut Vec<u8>,
211    exp: &mut i128,
212    // number of zeros after the decimal point
213    target_scale: Option<usize>,
214) {
215    debug_assert!(*exp >= 0);
216    debug_assert_ne!(digits.len(), 0);
217
218    let integer_zero_count = match exp.to_usize() {
219        Some(n) => n,
220        None => { return; }
221    };
222
223    // did not explicitly request precision, so we'll only
224    // implicitly right-pad if less than this threshold.
225    if target_scale.is_none() && integer_zero_count > 20 {
226        // no padding
227        return;
228    }
229
230    let fraction_zero_char_count;
231    let decimal_place_idx;
232
233    if let Some(frac_zero_count) = target_scale.and_then(NonZeroUsize::new) {
234        // add one char for '.' if target_scale is not zero
235        fraction_zero_char_count = frac_zero_count.get() + 1;
236        // indicate we'll need to add a decimal point
237        decimal_place_idx = Some(digits.len() + integer_zero_count);
238    } else {
239        fraction_zero_char_count = 0;
240        decimal_place_idx = None;
241    }
242
243    let total_additional_zeros = integer_zero_count.saturating_add(fraction_zero_char_count);
244
245    // no padding if out of bounds
246    if total_additional_zeros > FMT_MAX_INTEGER_PADDING {
247        return;
248    }
249
250    digits.resize(digits.len() + total_additional_zeros, b'0');
251    if let Some(decimal_place_idx) = decimal_place_idx {
252        digits[decimal_place_idx] = b'.';
253    }
254
255    // set exp to zero so it won't be written in `format_full_scale`
256    *exp = 0;
257}
258
259
260/// Insert decimal point into digits_ascii_be, rounding or padding with zeros when necessary
261///
262/// (digits_ascii_be, scale) represents a decimal with both integer and fractional digits.
263///
264fn format_ascii_digits_with_integer_and_fraction(
265    digits_ascii_be: &mut Vec<u8>,
266    scale: u64,
267    target_scale: u64,
268    rounder: NonDigitRoundingData,
269) {
270    debug_assert!(scale < digits_ascii_be.len() as u64, "No integer digits");
271    let mut digit_scale = scale;
272
273    // decimal has more fractional digits than requested: round (trimming insignificant digits)
274    if target_scale < scale {
275        let digit_count_to_remove = (scale - target_scale)
276                                    .to_usize()
277                                    .expect("Precision exceeds maximum usize");
278
279        let rounding_idx = NonZeroUsize::new(digits_ascii_be.len() - digit_count_to_remove)
280                           .expect("decimal must have integer digits");
281
282        // round and trim the digits at the 'rounding index'
283        let scale_diff = round_ascii_digits(digits_ascii_be, rounding_idx, rounder);
284
285        match scale_diff.checked_sub(digit_scale as usize) {
286            None | Some(0) => {
287                digit_scale -= scale_diff as u64;
288            }
289            Some(zeros_to_add) => {
290                digits_ascii_be.resize(digits_ascii_be.len() + zeros_to_add, b'0');
291                digit_scale = 0;
292            }
293        }
294    }
295
296    // ignore the decimal point if the target scale is zero
297    if target_scale != 0 {
298        // there are both integer and fractional digits
299        let integer_digit_count = (digits_ascii_be.len() as u64 - digit_scale)
300                                  .to_usize()
301                                  .expect("Number of digits exceeds maximum usize");
302
303
304        digits_ascii_be.insert(integer_digit_count, b'.');
305    }
306
307    if digit_scale < target_scale {
308        let trailing_zero_count = (target_scale - digit_scale)
309                                  .to_usize()
310                                  .expect("Too Big");
311
312        // precision required beyond scale
313        digits_ascii_be.resize(digits_ascii_be.len() + trailing_zero_count, b'0');
314        digit_scale += trailing_zero_count as u64;
315    }
316
317    debug_assert_eq!(digit_scale, target_scale);
318}
319
320
321/// Insert decimal point into digits_ascii_be, rounding or padding with zeros when necessary
322///
323/// (digits_ascii_be, scale) represents a decimal with only fractional digits.
324///
325fn format_ascii_digits_no_integer(
326    digits_ascii_be: &mut Vec<u8>,
327    scale: u64,
328    target_scale: u64,
329    rounder: NonDigitRoundingData,
330) {
331    use stdlib::cmp::Ordering::*;
332
333    debug_assert!(scale >= digits_ascii_be.len() as u64);
334    let leading_zeros = scale - digits_ascii_be.len() as u64;
335
336    match arithmetic::diff(target_scale, leading_zeros) {
337        // handle rounding point before the start of digits
338        (Less, intermediate_zeros) | (Equal, intermediate_zeros)  => {
339            // get insignificant digit
340            let (insig_digit, trailing_digits) = if intermediate_zeros > 0 {
341                (0, digits_ascii_be.as_slice())
342            } else {
343                (digits_ascii_be[0] - b'0', &digits_ascii_be[1..])
344            };
345
346            let insig_data = InsigData::from_digit_and_lazy_trailing_zeros(
347                rounder, insig_digit, || trailing_digits.iter().all(|&d| d == b'0')
348            );
349
350            let rounded_digit = insig_data.round_digit(0);
351            debug_assert_ne!(rounded_digit, 10);
352
353            digits_ascii_be.clear();
354
355            if target_scale > 0 {
356                digits_ascii_be.resize(target_scale as usize + 1, b'0');
357            }
358
359            digits_ascii_be.push(rounded_digit + b'0');
360
361            if target_scale > 0 {
362                digits_ascii_be[1] = b'.';
363            }
364        }
365        (Greater, sig_digit_count) => {
366            let significant_digit_count = sig_digit_count
367                                          .to_usize()
368                                          .and_then(NonZeroUsize::new)
369                                          .expect("Request overflow in sig_digit_count");
370
371            let mut digit_scale = scale;
372
373            // if 'digits_ascii_be' has more digits than requested, round
374            if significant_digit_count.get() < digits_ascii_be.len() {
375                let removed_digit_count = round_ascii_digits(
376                    digits_ascii_be, significant_digit_count, rounder
377                );
378
379                digit_scale -= removed_digit_count as u64;
380            }
381
382            // number of zeros to keep after the significant digits
383            let trailing_zeros = target_scale - digit_scale;
384
385            // expected length is target scale (number of digits after decimal point) + "0."
386            let dest_len = target_scale as usize + 2;
387
388            // number of significant digits is whatever is left in the digit vector
389            let sig_digit_count = digits_ascii_be.len();
390
391            // index where to store significant digits
392            let sig_digit_idx = dest_len - trailing_zeros as usize - sig_digit_count;
393
394            // fill output with zeros
395            digits_ascii_be.resize(dest_len, b'0');
396
397            // very likely case where there are digits after the decimal point
398            if digit_scale != 0 {
399                // copy significant digits to their index location
400                digits_ascii_be.copy_within(..sig_digit_count, sig_digit_idx);
401
402                // clear copied values
403                fill_slice(&mut digits_ascii_be[..sig_digit_count.min(sig_digit_idx)], b'0');
404            } else {
405                debug_assert_eq!(sig_digit_count, 1);
406            }
407
408            // add decimal point
409            digits_ascii_be[1] = b'.';
410        }
411    }
412}
413
414#[cfg(rust_1_50)]
415fn fill_slice<T: Clone>(v: &mut [T], value: T) {
416    v.fill(value);
417}
418
419#[cfg(not(rust_1_50))]
420fn fill_slice<T: Clone>(v: &mut [T], value: T) {
421    for i in v.iter_mut() {
422        *i = value.clone();
423    }
424}
425
426
427/// Format integer as {int}e+{exp}
428///
429/// Slightly different than scientific notation,
430///
431fn format_dotless_exponential(
432    f: &mut fmt::Formatter,
433    mut abs_int: String,
434    sign: Sign,
435    scale: i64,
436    e_symbol: &str,
437) -> fmt::Result {
438    debug_assert!(scale <= 0);
439
440    write!(abs_int, "{}{:+}", e_symbol, -scale).unwrap();
441    let non_negative = matches!(sign, Sign::Plus | Sign::NoSign);
442    f.pad_integral(non_negative, "", &abs_int)
443}
444
445fn format_exponential(
446    this: BigDecimalRef,
447    f: &mut fmt::Formatter,
448    abs_int: String,
449    e_symbol: &str,
450) -> fmt::Result {
451    // Steps:
452    //  1. Truncate integer based on precision
453    //  2. calculate exponent from the scale and the length of the internal integer
454    //  3. Place decimal point after a single digit of the number, or omit if there is only a single digit
455    //  4. Append `E{exponent}` and format the resulting string based on some `Formatter` flags
456
457    let exp = (this.scale as i128).neg();
458    let digits = abs_int.into_bytes();
459
460    format_exponential_bigendian_ascii_digits(
461        digits, this.sign, exp, f, e_symbol
462    )
463}
464
465
466fn format_exponential_bigendian_ascii_digits(
467    mut digits: Vec<u8>,
468    sign: Sign,
469    mut exp: i128,
470    f: &mut fmt::Formatter,
471    e_symbol: &str,
472) -> fmt::Result {
473    // how many zeros to pad at the end of the decimal
474    let mut extra_trailing_zero_count = 0;
475
476    if let Some(prec) = f.precision() {
477        // 'prec' is number of digits after the decimal point
478        let total_prec = prec + 1;
479
480        if total_prec < digits.len() {
481            // round to smaller precision
482            let rounder = NonDigitRoundingData::default_with_sign(sign);
483            let target_scale = NonZeroUsize::new(total_prec).unwrap();
484            let delta_exp = round_ascii_digits(&mut digits, target_scale, rounder);
485            exp += delta_exp as i128;
486        }
487
488        extra_trailing_zero_count = total_prec - digits.len();
489    }
490
491    let needs_decimal_point = digits.len() > 1 || extra_trailing_zero_count > 0;
492
493    let mut abs_int = String::from_utf8(digits).unwrap();
494
495    // Determine the exponent value based on the scale
496    //
497    // # First case: the integer representation falls completely behind the
498    //   decimal point.
499    //
500    //   Example of this.scale > abs_int.len():
501    //   0.000001234509876
502    //   abs_int.len() = 10
503    //   scale = 15
504    //   target is 1.234509876
505    //   exponent = -6
506    //
507    //   Example of this.scale == abs_int.len():
508    //   0.333333333333333314829616256247390992939472198486328125
509    //   abs_int.len() = 54
510    //   scale = 54
511    //   target is 3.33333333333333314829616256247390992939472198486328125
512    //   exponent = -1
513    //
514    // # Second case: the integer representation falls around, or before the
515    //   decimal point
516    //
517    //   ## Case 2.1, entirely before the decimal point.
518    //     Example of (abs_int.len() - this.scale) > abs_int.len():
519    //     123450987600000
520    //     abs_int.len() = 10
521    //     scale = -5
522    //     location = 15
523    //     target is 1.234509876
524    //     exponent = 14
525    //
526    //   ## Case 2.2, somewhere around the decimal point.
527    //     Example of (abs_int.len() - this.scale) < abs_int.len():
528    //     12.339999999999999857891452847979962825775146484375
529    //     abs_int.len() = 50
530    //     scale = 48
531    //     target is 1.2339999999999999857891452847979962825775146484375
532    //     exponent = 1
533    //
534    //     For the (abs_int.len() - this.scale) == abs_int.len() I couldn't
535    //     come up with an example
536    let exponent = abs_int.len() as i128 + exp - 1;
537
538    if needs_decimal_point {
539        // only add decimal point if there is more than 1 decimal digit
540        abs_int.insert(1, '.');
541    }
542
543    if extra_trailing_zero_count > 0 {
544        abs_int.extend(stdlib::iter::repeat('0').take(extra_trailing_zero_count));
545    }
546
547    // always print exponent in exponential mode
548    write!(abs_int, "{}{:+}", e_symbol, exponent)?;
549
550    let non_negative = matches!(sign, Sign::Plus | Sign::NoSign);
551    //pad_integral does the right thing although we have a decimal
552    f.pad_integral(non_negative, "", &abs_int)
553}
554
555
556/// Round big-endian ascii digits to given significant digit count,
557/// updating the scale appropriately
558///
559/// Returns the number of digits removed; this should be treated as the
560/// change in the decimal's scale, and should be subtracted from the scale
561/// when appropriate.
562///
563fn round_ascii_digits(
564    // bigendian ascii digits
565    digits_ascii_be: &mut Vec<u8>,
566    // number of significant digits to keep
567    significant_digit_count: NonZeroUsize,
568    // how to round
569    rounder: NonDigitRoundingData,
570) -> usize {
571    debug_assert!(significant_digit_count.get() < digits_ascii_be.len());
572
573    let (sig_digits, insig_digits) = digits_ascii_be.split_at(significant_digit_count.get());
574    let (&insig_digit, trailing_digits) = insig_digits.split_first().unwrap_or((&b'0', &[]));
575
576    let insig_data = InsigData::from_digit_and_lazy_trailing_zeros(
577        rounder, insig_digit - b'0', || trailing_digits.iter().all(|&d| d == b'0')
578    );
579
580    let rounding_digit_pos = significant_digit_count.get() - 1;
581    let sig_digit = sig_digits[rounding_digit_pos] - b'0';
582    let rounded_digit = insig_data.round_digit(sig_digit);
583
584    // record how many digits to remove (changes the 'scale')
585    let mut removed_digit_count = insig_digits.len();
586
587    // discard insignificant digits (and rounding digit)
588    digits_ascii_be.truncate(rounding_digit_pos);
589
590    if rounded_digit < 10 {
591        // simple case: no carrying/overflow, push rounded digit
592        digits_ascii_be.push(rounded_digit + b'0');
593        return removed_digit_count;
594    }
595
596    // handle carrying the 1
597    debug_assert!(rounded_digit == 10);
598
599    // carry the one past trailing 9's: replace them with zeros
600    let next_non_nine_rev_pos = digits_ascii_be.iter().rev().position(|&d| d != b'9');
601    match next_non_nine_rev_pos {
602        // number of nines to remove
603        Some(backwards_nine_count) => {
604            let digits_to_trim = backwards_nine_count + 1;
605            let idx = digits_ascii_be.len() - digits_to_trim;
606            // increment least significant non-nine zero
607            digits_ascii_be[idx] += 1;
608            // remove trailing nines
609            digits_ascii_be.truncate(idx + 1);
610            // count truncation
611            removed_digit_count += digits_to_trim;
612        }
613        // all nines! overflow to 1.000
614        None => {
615            digits_ascii_be.clear();
616            digits_ascii_be.push(b'1');
617            // count digit clearning
618            removed_digit_count += significant_digit_count.get();
619        }
620    }
621
622    // return the number of removed digits
623    return removed_digit_count;
624}
625
626
627#[inline(never)]
628pub(crate) fn write_scientific_notation<W: Write>(n: &BigDecimal, w: &mut W) -> fmt::Result {
629    if n.is_zero() {
630        return w.write_str("0e0");
631    }
632
633    if n.int_val.sign() == Sign::Minus {
634        w.write_str("-")?;
635    }
636
637    let digits = n.int_val.magnitude();
638
639    let dec_str = digits.to_str_radix(10);
640    let (first_digit, remaining_digits) = dec_str.as_str().split_at(1);
641    w.write_str(first_digit)?;
642    if !remaining_digits.is_empty() {
643        w.write_str(".")?;
644        w.write_str(remaining_digits)?;
645    }
646    write!(w, "e{}", remaining_digits.len() as i128 - n.scale as i128)
647}
648
649
650#[inline(never)]
651pub(crate) fn write_engineering_notation<W: Write>(n: &BigDecimal, out: &mut W) -> fmt::Result {
652    if n.is_zero() {
653        return out.write_str("0e0");
654    }
655
656    if n.int_val.sign() == Sign::Minus {
657        out.write_char('-')?;
658    }
659
660    let digits = n.int_val.magnitude();
661
662    let dec_str = digits.to_str_radix(10);
663    let digit_count = dec_str.len();
664
665    let top_digit_exponent = digit_count as i128 - n.scale as i128;
666
667    let shift_amount = match top_digit_exponent.rem_euclid(3) {
668        0 => 3,
669        i => i as usize,
670    };
671
672    let exp = top_digit_exponent - shift_amount as i128;
673
674    // handle adding zero padding
675    if let Some(padding_zero_count) = shift_amount.checked_sub(dec_str.len()) {
676        let zeros = &"000"[..padding_zero_count];
677        out.write_str(&dec_str)?;
678        out.write_str(zeros)?;
679        return write!(out, "e{}", exp);
680    }
681
682    let (head, rest) = dec_str.split_at(shift_amount);
683    debug_assert_eq!(exp % 3, 0);
684
685    out.write_str(head)?;
686
687    if !rest.is_empty() {
688        out.write_char('.')?;
689        out.write_str(rest)?;
690    }
691
692    return write!(out, "e{}", exp);
693}
694
695
696#[cfg(test)]
697#[allow(non_snake_case)]
698mod test {
699    use super::*;
700    use paste::*;
701
702    /// test case builder for mapping decimal-string to formatted-string
703    /// define test_fmt_function! macro to test your function
704    #[cfg(test)]
705    macro_rules! impl_case {
706        ($name:ident : $in:literal => $ex:literal) => {
707            #[test]
708            fn $name() {
709                let n: BigDecimal = $in.parse().unwrap();
710                let s = test_fmt_function!(n);
711                assert_eq!(&s, $ex);
712            }
713        };
714    }
715
716    /// "Mock" Formatter
717    ///
718    /// Given callable, forwards formatter to callable.
719    /// Required work-around due to lack of constructor in fmt::Formatter
720    ///
721    struct Fmt<F>(F)
722        where F: Fn(&mut fmt::Formatter) -> fmt::Result;
723
724    impl<F> fmt::Display for Fmt<F>
725        where F: Fn(&mut fmt::Formatter) -> fmt::Result
726    {
727        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
728            // call closure with given formatter
729            (self.0)(f)
730        }
731    }
732
733    impl<F> fmt::Debug for Fmt<F>
734        where F: Fn(&mut fmt::Formatter) -> fmt::Result
735    {
736        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
737            (self.0)(f)
738        }
739    }
740
741    mod dynamic_fmt {
742        use super::*;
743
744        macro_rules! test_fmt_function {
745            ($n:ident) => {{
746                format!("{}", Fmt(|f| dynamically_format_decimal($n.to_ref(), f, 2, 9)))
747            }};
748        }
749
750        impl_case!(case_0d123: "0.123" => "0.123");
751        impl_case!(case_0d0123: "0.0123" => "0.0123");
752        impl_case!(case_0d00123: "0.00123" => "0.00123");
753        impl_case!(case_0d000123: "0.000123" => "1.23E-4");
754
755        impl_case!(case_123d: "123." => "123");
756        impl_case!(case_123de1: "123.e1" => "1230");
757    }
758
759    mod fmt_options {
760        use super::*;
761
762        macro_rules! impl_case {
763            ($name:ident: $fmt:literal => $expected:literal) => {
764                #[test]
765                fn $name() {
766                    let x = test_input();
767                    let y = format!($fmt, x);
768                    assert_eq!(y, $expected);
769                }
770            };
771        }
772
773        mod dec_1 {
774            use super::*;
775
776            fn test_input() -> BigDecimal {
777                "1".parse().unwrap()
778            }
779
780            impl_case!(fmt_default:      "{}" => "1");
781            impl_case!(fmt_d1:        "{:.1}" => "1.0");
782            impl_case!(fmt_d4:        "{:.4}" => "1.0000");
783            impl_case!(fmt_4d1:      "{:4.1}" => " 1.0");
784            impl_case!(fmt_r4d1:    "{:>4.1}" => " 1.0");
785            impl_case!(fmt_l4d1:    "{:<4.1}" => "1.0 ");
786            impl_case!(fmt_p05d1:  "{:+05.1}" => "+01.0");
787
788            impl_case!(fmt_e:      "{:e}" => "1e+0");
789            impl_case!(fmt_E:      "{:E}" => "1E+0");
790        }
791
792        mod dec_1e1 {
793            use super::*;
794
795            fn test_input() -> BigDecimal {
796                BigDecimal::new(1.into(), -1)
797            }
798
799            impl_case!(fmt_default:      "{}" => "10");
800            impl_case!(fmt_debug:      "{:?}" => "BigDecimal(sign=Plus, scale=-1, digits=[1])");
801            impl_case!(fmt_debug_alt: "{:#?}" => "BigDecimal(\"1e1\")");
802            impl_case!(fmt_d0:        "{:.0}" => "10");
803            impl_case!(fmt_d1:        "{:.1}" => "10.0");
804            impl_case!(fmt_d2:        "{:.2}" => "10.00");
805        }
806
807        mod dec_1en1 {
808            use super::*;
809
810            fn test_input() -> BigDecimal {
811                BigDecimal::new(1.into(), 1)
812            }
813
814            impl_case!(fmt_default:      "{}" => "0.1");
815            impl_case!(fmt_d0:        "{:.0}" => "0");
816            impl_case!(fmt_d1:        "{:.1}" => "0.1");
817            impl_case!(fmt_d2:        "{:.2}" => "0.10");
818        }
819
820        mod dec_9en1 {
821            use super::*;
822
823            fn test_input() -> BigDecimal {
824                BigDecimal::new(9.into(), 1)
825            }
826
827            impl_case!(fmt_default:      "{}" => "0.9");
828            impl_case!(fmt_d0:        "{:.0}" => "1");
829            impl_case!(fmt_d1:        "{:.1}" => "0.9");
830            impl_case!(fmt_d4:        "{:.4}" => "0.9000");
831        }
832
833        mod dec_800en3 {
834            use super::*;
835
836            fn test_input() -> BigDecimal {
837                BigDecimal::new(800.into(), 3)
838            }
839
840            impl_case!(fmt_default:      "{}" => "0.800");
841            impl_case!(fmt_d0:        "{:.0}" => "1");
842            impl_case!(fmt_d1:        "{:.1}" => "0.8");
843            impl_case!(fmt_d3:        "{:.3}" => "0.800");
844            impl_case!(fmt_d9:        "{:.9}" => "0.800000000");
845        }
846
847        mod dec_123456 {
848            use super::*;
849
850            fn test_input() -> BigDecimal {
851                "123456".parse().unwrap()
852            }
853
854            impl_case!(fmt_default:      "{}" => "123456");
855            impl_case!(fmt_d1:        "{:.1}" => "123456.0");
856            impl_case!(fmt_d4:        "{:.4}" => "123456.0000");
857            impl_case!(fmt_4d1:      "{:4.1}" => "123456.0");
858            impl_case!(fmt_15d2:    "{:15.2}" => "      123456.00");
859            impl_case!(fmt_r15d2:  "{:>15.2}" => "      123456.00");
860            impl_case!(fmt_l15d2:  "{:<15.2}" => "123456.00      ");
861            impl_case!(fmt_p05d1:  "{:+05.7}" => "+123456.0000000");
862        }
863
864        mod dec_d099995 {
865            use super::*;
866
867            fn test_input() -> BigDecimal {
868                ".099995".parse().unwrap()
869            }
870
871            impl_case!(fmt_default:  "{}" => "0.099995");
872            impl_case!(fmt_d0:  "{:.0}" => "0");
873            impl_case!(fmt_d1:  "{:.1}" => "0.1");
874            impl_case!(fmt_d3:  "{:.3}" => "0.100");
875        }
876
877        mod dec_d9999999 {
878            use super::*;
879
880            fn test_input() -> BigDecimal {
881                ".9999999".parse().unwrap()
882            }
883
884            impl_case!(fmt_default:  "{}" => "0.9999999");
885            impl_case!(fmt_d0:  "{:.0}" => "1");
886            impl_case!(fmt_d1:  "{:.1}" => "1.0");
887            impl_case!(fmt_d3:  "{:.3}" => "1.000");
888        }
889
890        mod dec_9999999 {
891            use super::*;
892
893            fn test_input() -> BigDecimal {
894                "9999999".parse().unwrap()
895            }
896
897            impl_case!(fmt_default:  "{}" => "9999999");
898            impl_case!(fmt_d1:  "{:.1}" => "9999999.0");
899            impl_case!(fmt_d8:  "{:.8}" => "9999999.00000000");
900
901            impl_case!(fmt_e:  "{:e}" => "9.999999e+6");
902            impl_case!(fmt_E:  "{:E}" => "9.999999E+6");
903            impl_case!(fmt_d0e:  "{:.0e}" => "1e+7");
904            impl_case!(fmt_d1e:  "{:.1e}" => "1.0e+7");
905            impl_case!(fmt_d2e:  "{:.2e}" => "1.00e+7");
906            impl_case!(fmt_d4e:  "{:.4e}" => "1.0000e+7");
907            impl_case!(fmt_d6e:  "{:.6e}" => "9.999999e+6");
908            impl_case!(fmt_d7e:  "{:.7e}" => "9.9999990e+6");
909            impl_case!(fmt_d10e:  "{:.10e}" => "9.9999990000e+6");
910        }
911
912        mod dec_19073d97235939614856 {
913            use super::*;
914
915            fn test_input() -> BigDecimal {
916                "19073.97235939614856".parse().unwrap()
917            }
918
919            impl_case!(fmt_default:      "{}" => "19073.97235939614856");
920            impl_case!(fmt_pd7:      "{:+.7}" => "+19073.9723594");
921            impl_case!(fmt_d0:        "{:.0}" => "19074");
922            impl_case!(fmt_d1:        "{:.1}" => "19074.0");
923            impl_case!(fmt_d3:        "{:.3}" => "19073.972");
924            impl_case!(fmt_d4:        "{:.4}" => "19073.9724");
925            impl_case!(fmt_8d3:      "{:8.3}" => "19073.972");
926            impl_case!(fmt_10d3:    "{:10.3}" => " 19073.972");
927            impl_case!(fmt_010d3:  "{:010.3}" => "019073.972");
928        }
929
930        mod dec_10950633712399d557 {
931            use super::*;
932
933            fn test_input() -> BigDecimal {
934                "10950633712399.557".parse().unwrap()
935            }
936
937            impl_case!(fmt_default:  "{}" => "10950633712399.557");
938            impl_case!(fmt_d0:    "{:.0}" => "10950633712400");
939            impl_case!(fmt_d1:    "{:.1}" => "10950633712399.6");
940            impl_case!(fmt_d2:    "{:.2}" => "10950633712399.56");
941            impl_case!(fmt_d3:    "{:.3}" => "10950633712399.557");
942            impl_case!(fmt_d4:    "{:.4}" => "10950633712399.5570");
943        }
944
945        mod dec_n90037659d6902 {
946            use super::*;
947
948            fn test_input() -> BigDecimal {
949                "-90037659.6905".parse().unwrap()
950            }
951
952            impl_case!(fmt_default:      "{}" => "-90037659.6905");
953            impl_case!(fmt_debug:      "{:?}" => "BigDecimal(sign=Minus, scale=4, digits=[900376596905])");
954            impl_case!(fmt_debug_alt: "{:#?}" => "BigDecimal(\"-900376596905e-4\")");
955            impl_case!(fmt_pd7:      "{:+.7}" => "-90037659.6905000");
956            impl_case!(fmt_d0:        "{:.0}" => "-90037660");
957            impl_case!(fmt_d3:        "{:.3}" => "-90037659.690");
958            impl_case!(fmt_d4:        "{:.4}" => "-90037659.6905");
959            impl_case!(fmt_14d4:    "{:14.4}" => "-90037659.6905");
960            impl_case!(fmt_15d4:    "{:15.4}" => " -90037659.6905");
961            impl_case!(fmt_l17d5:  "{:<17.5}" => "-90037659.69050  ");
962        }
963
964        mod dec_0d0002394899999500 {
965            use super::*;
966
967            fn test_input() -> BigDecimal {
968                "0.0002394899999500".parse().unwrap()
969            }
970
971            impl_case!(fmt_default:    "{}" => "0.0002394899999500");
972            impl_case!(fmt_d0:      "{:.0}" => "0");
973            impl_case!(fmt_d1:      "{:.1}" => "0.0");
974            impl_case!(fmt_d3:      "{:.3}" => "0.000");
975            impl_case!(fmt_d4:      "{:.4}" => "0.0002");
976            impl_case!(fmt_d5:      "{:.5}" => "0.00024");
977            impl_case!(fmt_d10:    "{:.10}" => "0.0002394900");
978            impl_case!(fmt_d13:    "{:.13}" => "0.0002394900000");
979            impl_case!(fmt_d14:    "{:.14}" => "0.00023948999995");
980            impl_case!(fmt_d20:    "{:.20}" => "0.00023948999995000000");
981
982        }
983
984        mod dec_1764031078en13 {
985            use super::*;
986
987            fn test_input() -> BigDecimal {
988                BigDecimal::new(1764031078.into(), 13)
989            }
990
991            impl_case!(fmt_default:    "{}" => "0.0001764031078");
992            impl_case!(fmt_d1:      "{:.1}" => "0.0");
993            impl_case!(fmt_d3:      "{:.3}" => "0.000");
994            impl_case!(fmt_d4:      "{:.4}" => "0.0002");
995            impl_case!(fmt_d5:      "{:.5}" => "0.00018");
996            impl_case!(fmt_d13:    "{:.13}" => "0.0001764031078");
997            impl_case!(fmt_d20:    "{:.20}" => "0.00017640310780000000");
998
999        }
1000
1001        mod dec_1e15 {
1002            use super::*;
1003
1004            fn test_input() -> BigDecimal {
1005                "1e15".parse().unwrap()
1006            }
1007
1008            impl_case!(fmt_default:        "{}" => "1000000000000000");
1009            impl_case!(fmt_d0:          "{:.0}" => "1000000000000000");
1010            impl_case!(fmt_d1:          "{:.1}" => "1000000000000000.0");
1011        }
1012
1013        mod dec_1e16 {
1014            use super::*;
1015
1016            fn test_input() -> BigDecimal {
1017                "1e16".parse().unwrap()
1018            }
1019
1020            impl_case!(fmt_default:        "{}" => "1e+16");
1021            impl_case!(fmt_d0:          "{:.0}" => "10000000000000000");
1022            impl_case!(fmt_d2:          "{:.2}" => "10000000000000000.00");
1023        }
1024
1025
1026        mod dec_491326en12 {
1027            use super::*;
1028
1029            fn test_input() -> BigDecimal {
1030                "491326e-12".parse().unwrap()
1031            }
1032
1033            impl_case!(fmt_default:     "{}" => "4.91326E-7");
1034            impl_case!(fmt_d0:       "{:.0}" => "0");
1035            impl_case!(fmt_d1:       "{:.1}" => "0.0");
1036            impl_case!(fmt_d3:       "{:.3}" => "0.000");
1037            impl_case!(fmt_d5:       "{:.5}" => "0.00000");
1038            impl_case!(fmt_d6:       "{:.7}" => "0.0000005");
1039            impl_case!(fmt_d9:       "{:.9}" => "0.000000491");
1040            impl_case!(fmt_d20:     "{:.20}" => "0.00000049132600000000");
1041
1042            impl_case!(fmt_d0e:     "{:.0E}" => "5E-7");
1043            impl_case!(fmt_d1e:     "{:.1E}" => "4.9E-7");
1044            impl_case!(fmt_d3e:     "{:.3E}" => "4.913E-7");
1045            impl_case!(fmt_d5e:     "{:.5E}" => "4.91326E-7");
1046            impl_case!(fmt_d6e:     "{:.6E}" => "4.913260E-7");
1047        }
1048
1049        mod dec_0d00003102564500 {
1050            use super::*;
1051
1052            fn test_input() -> BigDecimal {
1053                "0.00003102564500".parse().unwrap()
1054            }
1055
1056            impl_case!(fmt_default: "{}" => "0.00003102564500");
1057            impl_case!(fmt_d0:   "{:.0}" => "0");
1058            impl_case!(fmt_d1:   "{:.1}" => "0.0");
1059            impl_case!(fmt_d2:   "{:.2}" => "0.00");
1060            impl_case!(fmt_d4:   "{:.4}" => "0.0000");
1061            impl_case!(fmt_d5:   "{:.5}" => "0.00003");
1062            impl_case!(fmt_d10:  "{:.10}" => "0.0000310256");
1063            impl_case!(fmt_d14:  "{:.14}" => "0.00003102564500");
1064            impl_case!(fmt_d17:  "{:.17}" => "0.00003102564500000");
1065
1066            impl_case!(fmt_e:      "{:e}" => "3.102564500e-5");
1067            impl_case!(fmt_de:    "{:.e}" => "3.102564500e-5");
1068            impl_case!(fmt_d0e:  "{:.0e}" => "3e-5");
1069            impl_case!(fmt_d1e:  "{:.1e}" => "3.1e-5");
1070            impl_case!(fmt_d4e:  "{:.4e}" => "3.1026e-5");
1071        }
1072
1073        mod dec_1en100000 {
1074            use super::*;
1075
1076            fn test_input() -> BigDecimal {
1077                "1E-10000".parse().unwrap()
1078            }
1079
1080            impl_case!(fmt_default: "{}" => "1E-10000");
1081            impl_case!(fmt_d:    "{:.0}" => "0");
1082            impl_case!(fmt_d1:   "{:.1}" => "0.0");
1083            impl_case!(fmt_d4:   "{:.4}" => "0.0000");
1084
1085            impl_case!(fmt_d1E: "{:.1E}" => "1.0E-10000");
1086            impl_case!(fmt_d4E: "{:.4E}" => "1.0000E-10000");
1087        }
1088
1089        mod dec_1e100000 {
1090            use super::*;
1091
1092            fn test_input() -> BigDecimal {
1093                "1e100000".parse().unwrap()
1094            }
1095
1096            impl_case!(fmt_default: "{}" => "1e+100000");
1097            impl_case!(fmt_d1: "{:.1}" => "1e+100000");
1098            impl_case!(fmt_d4: "{:.4}" => "1e+100000");
1099        }
1100
1101
1102        mod dec_1234506789E5 {
1103            use super::*;
1104
1105            fn test_input() -> BigDecimal {
1106                BigDecimal::new(1234506789.into(), -5)
1107            }
1108
1109            impl_case!(fmt_default: "{}" => "123450678900000");
1110            impl_case!(fmt_d1: "{:.1}" => "123450678900000.0");
1111            impl_case!(fmt_d3: "{:.3}" => "123450678900000.000");
1112            impl_case!(fmt_d4: "{:.4}" => "123450678900000.0000");
1113            impl_case!(fmt_l13d4: "{:<23.4}" => "123450678900000.0000   ");
1114            impl_case!(fmt_r13d4: "{:>23.4}" => "   123450678900000.0000");
1115        }
1116
1117        mod dec_1234506789E15 {
1118            use super::*;
1119
1120            fn test_input() -> BigDecimal {
1121                BigDecimal::new(1234506789.into(), -15)
1122            }
1123
1124            impl_case!(fmt_default: "{}" => "1234506789000000000000000");
1125            impl_case!(fmt_d1: "{:.1}" => "1234506789000000000000000.0");
1126            impl_case!(fmt_d3: "{:.3}" => "1234506789000000000000000.000");
1127            impl_case!(fmt_l13d4: "{:<+32.2}" => "+1234506789000000000000000.00   ");
1128            impl_case!(fmt_r13d4: "{:>+32.2}" => "   +1234506789000000000000000.00");
1129        }
1130
1131        mod dec_13400476439814628800E2502 {
1132            use super::*;
1133
1134            fn test_input() -> BigDecimal {
1135                BigDecimal::new(13400476439814628800u64.into(), -2502)
1136            }
1137
1138            impl_case!(fmt_default: "{}" => "13400476439814628800e+2502");
1139            impl_case!(fmt_d1: "{:.1}" => "13400476439814628800e+2502");
1140        }
1141
1142        mod dec_d9999 {
1143            use super::*;
1144
1145            fn test_input() -> BigDecimal {
1146                "0.9999".parse().unwrap()
1147            }
1148
1149            impl_case!(fmt_default:      "{}" => "0.9999");
1150            impl_case!(fmt_d0:        "{:.0}" => "1");
1151            impl_case!(fmt_d1:        "{:.1}" => "1.0");
1152            impl_case!(fmt_d2:        "{:.2}" => "1.00");
1153            impl_case!(fmt_d3:        "{:.3}" => "1.000");
1154            impl_case!(fmt_d4:        "{:.4}" => "0.9999");
1155            impl_case!(fmt_d6:        "{:.6}" => "0.999900");
1156        }
1157
1158        mod dec_9d99 {
1159            use super::*;
1160
1161            fn test_input() -> BigDecimal {
1162                "9.99".parse().unwrap()
1163            }
1164
1165            impl_case!(fmt_default:      "{}" => "9.99");
1166            impl_case!(fmt_d0:        "{:.0}" => "10");
1167            impl_case!(fmt_d1:        "{:.1}" => "10.0");
1168            impl_case!(fmt_d2:        "{:.2}" => "9.99");
1169            impl_case!(fmt_d3:        "{:.3}" => "9.990");
1170        }
1171    }
1172
1173    mod fmt_boundaries {
1174        use super::*;
1175
1176        macro_rules! impl_case {
1177            ( $name:ident: $src:expr => $expected:literal ) => {
1178                #[test]
1179                fn $name() {
1180                    let src = $src;
1181                    let bd: BigDecimal = src.parse().unwrap();
1182                    let result = bd.to_string();
1183                    assert_eq!(result, $expected);
1184
1185                    let round_trip = BigDecimal::from_str(&result).unwrap();
1186                    assert_eq!(round_trip, bd);
1187
1188                    let sci = bd.to_scientific_notation();
1189                    let sci_round_trip = BigDecimal::from_str(&sci).unwrap();
1190                    assert_eq!(sci_round_trip, bd);
1191
1192                    let eng = bd.to_engineering_notation();
1193                    let eng_round_trip = BigDecimal::from_str(&eng).unwrap();
1194                    assert_eq!(eng_round_trip, bd);
1195                }
1196            };
1197            ( (eng-check-invalid) $name:ident: $src:expr => $expected:literal ) => {
1198                #[test]
1199                fn $name() {
1200                    let src = $src;
1201                    let bd: BigDecimal = src.parse().unwrap();
1202                    let result = bd.to_string();
1203                    assert_eq!(result, $expected);
1204
1205                    let round_trip = BigDecimal::from_str(&result).unwrap();
1206                    assert_eq!(round_trip, bd);
1207
1208                    let sci = bd.to_scientific_notation();
1209                    let sci_round_trip = BigDecimal::from_str(&sci).unwrap();
1210                    assert_eq!(sci_round_trip, bd);
1211
1212                    let eng = bd.to_engineering_notation();
1213                    let eng_round_trip = BigDecimal::from_str(&eng);
1214                    assert!(eng_round_trip.is_err());
1215                }
1216            };
1217            ( (panics) $name:ident: $src:expr ) => {
1218                #[test]
1219                #[should_panic]
1220                fn $name() {
1221                    let src = $src;
1222                    let _bd: BigDecimal = src.parse().unwrap();
1223                }
1224            };
1225        }
1226
1227
1228        impl_case!(test_max: format!("1E{}", i64::MAX) => "1e+9223372036854775807");
1229        impl_case!(test_max_multiple_digits: format!("314156E{}", i64::MAX) => "314156e+9223372036854775807");
1230        impl_case!(test_min_scale: "1E9223372036854775807" => "1e+9223372036854775807");
1231
1232        impl_case!((eng-check-invalid) test_max_scale: "1E-9223372036854775807" => "1E-9223372036854775807");
1233        impl_case!(test_min_multiple_digits: format!("271828182E-{}", i64::MAX) => "2.71828182E-9223372036854775799");
1234
1235        impl_case!((panics) test_max_exp_overflow: "1E9223372036854775809");
1236        impl_case!((panics) test_min_exp_overflow: "1E-9223372036854775808");
1237    }
1238
1239    #[test]
1240    fn test_fmt() {
1241        let vals = vec![
1242            // b  s (      {}     {:.1}        {:.4}    {:4.1}   {:+05.1}   {:<4.1}
1243            (1, 0,  (     "1",    "1.0",    "1.0000",   " 1.0",   "+01.0",   "1.0 " )),
1244            (1, 1,  (   "0.1",    "0.1",    "0.1000",   " 0.1",   "+00.1",   "0.1 " )),
1245            (1, 2,  (  "0.01",    "0.0",    "0.0100",   " 0.0",   "+00.0",   "0.0 " )),
1246            (1, -2, (   "100",  "100.0",  "100.0000",  "100.0",  "+100.0",  "100.0" )),
1247            (-1, 0, (    "-1",   "-1.0",   "-1.0000",   "-1.0",   "-01.0",   "-1.0" )),
1248            (-1, 1, (  "-0.1",   "-0.1",   "-0.1000",   "-0.1",   "-00.1",   "-0.1" )),
1249            (-1, 2, ( "-0.01",   "-0.0",   "-0.0100",   "-0.0",   "-00.0",   "-0.0" )),
1250        ];
1251        for (i, scale, results) in vals {
1252            let x = BigDecimal::new(num_bigint::BigInt::from(i), scale);
1253            assert_eq!(format!("{}", x), results.0);
1254            assert_eq!(format!("{:.1}", x), results.1);
1255            assert_eq!(format!("{:.4}", x), results.2);
1256            assert_eq!(format!("{:4.1}", x), results.3);
1257            assert_eq!(format!("{:+05.1}", x), results.4);
1258            assert_eq!(format!("{:<4.1}", x), results.5);
1259        }
1260    }
1261
1262
1263    mod fmt_debug {
1264        use super::*;
1265
1266        macro_rules! impl_case {
1267            ($name:ident: $input:literal => $expected:literal => $expected_alt:literal) => {
1268                paste! {
1269                    #[test]
1270                    fn $name() {
1271                        let x: BigDecimal = $input.parse().unwrap();
1272                        let y = format!("{:?}", x);
1273                        assert_eq!(y, $expected);
1274                    }
1275
1276                    #[test]
1277                    fn [< $name _alt >]() {
1278                        let x: BigDecimal = $input.parse().unwrap();
1279                        let y = format!("{:#?}", x);
1280                        assert_eq!(y, $expected_alt);
1281                    }
1282                }
1283            }
1284        }
1285
1286        impl_case!(case_0: "0" => r#"BigDecimal(sign=NoSign, scale=0, digits=[])"#
1287                               => r#"BigDecimal("0e0")"#);
1288
1289        impl_case!(case_n0: "-0" => r#"BigDecimal(sign=NoSign, scale=0, digits=[])"#
1290                               => r#"BigDecimal("0e0")"#);
1291
1292        impl_case!(case_1: "1" => r#"BigDecimal(sign=Plus, scale=0, digits=[1])"#
1293                               => r#"BigDecimal("1e0")"#);
1294
1295        impl_case!(case_123_400: "123.400" => r#"BigDecimal(sign=Plus, scale=3, digits=[123400])"#
1296                                           => r#"BigDecimal("123400e-3")"#);
1297
1298        impl_case!(case_123_4en2: "123.4e-2" => r#"BigDecimal(sign=Plus, scale=3, digits=[1234])"#
1299                                             => r#"BigDecimal("1234e-3")"#);
1300
1301        impl_case!(case_123_456:   "123.456" => r#"BigDecimal(sign=Plus, scale=3, digits=[123456])"#
1302                                             => r#"BigDecimal("123456e-3")"#);
1303
1304        impl_case!(case_01_20:       "01.20" => r#"BigDecimal(sign=Plus, scale=2, digits=[120])"#
1305                                             => r#"BigDecimal("120e-2")"#);
1306
1307        impl_case!(case_1_20:         "1.20" => r#"BigDecimal(sign=Plus, scale=2, digits=[120])"#
1308                                             => r#"BigDecimal("120e-2")"#);
1309        impl_case!(case_01_2e3:     "01.2E3" => r#"BigDecimal(sign=Plus, scale=-2, digits=[12])"#
1310                                             => r#"BigDecimal("12e2")"#);
1311
1312        impl_case!(case_avagadro: "6.02214076e1023" => r#"BigDecimal(sign=Plus, scale=-1015, digits=[602214076])"#
1313                                                    => r#"BigDecimal("602214076e1015")"#);
1314
1315        impl_case!(case_1e99999999999999 : "1e99999999999999" => r#"BigDecimal(sign=Plus, scale=-99999999999999, digits=[1])"#
1316                                                              => r#"BigDecimal("1e99999999999999")"#);
1317
1318        impl_case!(case_n144d3308279 : "-144.3308279" => r#"BigDecimal(sign=Minus, scale=7, digits=[1443308279])"#
1319                                                      => r#"BigDecimal("-1443308279e-7")"#);
1320
1321        impl_case!(case_n349983058835858339619e2 : "-349983058835858339619e2"
1322                                                      => r#"BigDecimal(sign=Minus, scale=-2, digits=[17941665509086410531, 18])"#
1323                                                      => r#"BigDecimal("-349983058835858339619e2")"#);
1324    }
1325
1326    mod write_scientific_notation {
1327        use super::*;
1328
1329        macro_rules! test_fmt_function {
1330            ($n:expr) => { $n.to_scientific_notation() };
1331        }
1332
1333        impl_case!(case_4_1592480782835e9 : "4159248078.2835" => "4.1592480782835e9");
1334        impl_case!(case_1_234e_5 : "0.00001234" => "1.234e-5");
1335        impl_case!(case_0 : "0" => "0e0");
1336        impl_case!(case_1 : "1" => "1e0");
1337        impl_case!(case_2_00e0 : "2.00" => "2.00e0");
1338        impl_case!(case_neg_5_70e1 : "-57.0" => "-5.70e1");
1339    }
1340
1341    mod write_engineering_notation {
1342        use super::*;
1343
1344        macro_rules! test_fmt_function {
1345            ($n:expr) => { $n.to_engineering_notation() };
1346        }
1347
1348        impl_case!(case_4_1592480782835e9 : "4159248078.2835" => "4.1592480782835e9");
1349        impl_case!(case_12_34e_6 : "0.00001234" => "12.34e-6");
1350        impl_case!(case_0 : "0" => "0e0");
1351        impl_case!(case_1 : "1" => "1e0");
1352        impl_case!(case_2_00e0 : "2.00" => "2.00e0");
1353        impl_case!(case_neg_5_70e1 : "-57.0" => "-57.0e0");
1354        impl_case!(case_5_31e4 : "5.31e4" => "53.1e3");
1355        impl_case!(case_5_31e5 : "5.31e5" => "531e3");
1356        impl_case!(case_5_31e6 : "5.31e6" => "5.31e6");
1357        impl_case!(case_5_31e7 : "5.31e7" => "53.1e6");
1358
1359        impl_case!(case_1e2 : "1e2" => "100e0");
1360        impl_case!(case_1e119 : "1e19" => "10e18");
1361        impl_case!(case_1e3000 : "1e3000" => "1e3000");
1362        impl_case!(case_4_2e7 : "4.2e7" => "42e6");
1363        impl_case!(case_4_2e8 : "4.2e8" => "420e6");
1364
1365        impl_case!(case_4e99999999999999 : "4e99999999999999" => "4e99999999999999");
1366        impl_case!(case_4e99999999999998 : "4e99999999999998" => "400e99999999999996");
1367        impl_case!(case_44e99999999999998 : "44e99999999999998" => "4.4e99999999999999");
1368        impl_case!(case_4e99999999999997 : "4e99999999999997" => "40e99999999999996");
1369        impl_case!(case_41e99999999999997 : "41e99999999999997" => "410e99999999999996");
1370        impl_case!(case_413e99999999999997 : "413e99999999999997" => "4.13e99999999999999");
1371        // impl_case!(case_413e99999999999997 : "413e99999999999997" => "4.13e99999999999999");
1372    }
1373}
1374
1375
1376#[cfg(all(test, property_tests))]
1377mod proptests {
1378    use super::*;
1379    use paste::paste;
1380    use proptest::prelude::*;
1381    use proptest::num::f64::NORMAL as NormalF64;
1382
1383
1384    macro_rules! impl_parsing_test {
1385        ($t:ty) => {
1386            paste! { proptest! {
1387                #[test]
1388                fn [< roudtrip_to_str_and_back_ $t >](n: $t) {
1389                    let original = BigDecimal::from(n);
1390                    let display = format!("{}", original);
1391                    let parsed = display.parse::<BigDecimal>().unwrap();
1392
1393                    prop_assert_eq!(&original, &parsed);
1394                }
1395            } }
1396        };
1397        (from-float $t:ty) => {
1398            paste! { proptest! {
1399                #[test]
1400                fn [< roudtrip_to_str_and_back_ $t >](n: $t) {
1401                    let original = BigDecimal::try_from(n).unwrap();
1402                    let display = format!("{}", original);
1403                    let parsed = display.parse::<BigDecimal>().unwrap();
1404
1405                    prop_assert_eq!(&original, &parsed);
1406                }
1407            } }
1408        };
1409    }
1410
1411    impl_parsing_test!(u8);
1412    impl_parsing_test!(u16);
1413    impl_parsing_test!(u32);
1414    impl_parsing_test!(u64);
1415    impl_parsing_test!(u128);
1416
1417    impl_parsing_test!(i8);
1418    impl_parsing_test!(i16);
1419    impl_parsing_test!(i32);
1420    impl_parsing_test!(i64);
1421    impl_parsing_test!(i128);
1422
1423    impl_parsing_test!(from-float f32);
1424    impl_parsing_test!(from-float f64);
1425
1426    proptest! {
1427        #![proptest_config(ProptestConfig::with_cases(32_000))]
1428
1429        #[test]
1430        fn float_formatting(f in NormalF64, prec in 0..21usize) {
1431            let d = BigDecimal::from_f64(f).unwrap();
1432            let f_fmt = format!("{f:.prec$}");
1433            let d_fmt = format!("{d:.prec$}").replace("+", "");
1434            prop_assert_eq!(f_fmt, d_fmt);
1435        }
1436    }
1437
1438    proptest! {
1439        #![proptest_config(ProptestConfig::with_cases(1000))]
1440
1441        #[test]
1442        fn scientific_notation_roundtrip(f: f64) {
1443            prop_assume!(!f.is_nan() && !f.is_infinite());
1444            let n = BigDecimal::from_f64(f).unwrap();
1445            let s = n.to_scientific_notation();
1446            let m: BigDecimal = s.parse().unwrap();
1447            prop_assert_eq!(n, m);
1448        }
1449
1450        #[test]
1451        fn engineering_notation_roundtrip(f: f64) {
1452            prop_assume!(!f.is_nan() && !f.is_infinite());
1453            let n = BigDecimal::from_f64(f).unwrap();
1454            let s = n.to_engineering_notation();
1455            let m: BigDecimal = s.parse().unwrap();
1456            prop_assert_eq!(n, m);
1457        }
1458    }
1459}