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