fixed_decimal/
decimal.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use smallvec::SmallVec;
6
7use core::cmp;
8use core::cmp::Ordering;
9use core::fmt;
10use core::ops::RangeInclusive;
11use core::str::FromStr;
12
13use crate::{uint_iterator::IntIterator, IncrementLike, NoIncrement};
14#[cfg(feature = "ryu")]
15use crate::{FloatPrecision, LimitError};
16use crate::{ParseError, RoundingIncrement, UnsignedRoundingMode};
17
18// UnsignedDecimal assumes usize (digits.len()) is at least as big as a u16
19#[cfg(not(any(
20    target_pointer_width = "16",
21    target_pointer_width = "32",
22    target_pointer_width = "64"
23)))]
24compile_error!("The fixed_decimal crate only works if usizes are at least the size of a u16");
25
26/// A struct containing decimal digits with efficient iteration and manipulation by magnitude
27/// (power of 10).
28///
29/// Supports a mantissa of non-zero digits and a number of leading and trailing
30/// zeros; used for formatting and plural selection.
31///
32/// # Data Types
33///
34/// The following types can be converted to a [`UnsignedDecimal`]:
35///
36/// - Integers, unsigned
37/// - Strings representing an arbitrary-precision decimal
38/// - Floating point values (using the `ryu` feature)
39///
40/// To create a [`UnsignedDecimal`] with fraction digits, either create it from an integer and then
41/// call [`UnsignedDecimal::multiplied_pow10`], create it from a string, or (when the `ryu` feature is
42/// enabled) create it from a floating point value using [`UnsignedDecimal::try_from_f64`].
43///
44/// # Magnitude and Position
45///
46/// Each digit in a `FixedDecimal` is indexed by a *magnitude*, or the digit's power of 10.
47/// Illustration for the number "12.34":
48///
49/// | Magnitude | Digit | Description      |
50/// |-----------|-------|------------------|
51/// | 1         | 1     | Tens place       |
52/// | 0         | 2     | Ones place       |
53/// | -1        | 3     | Tenths place     |
54/// | -2        | 4     | Hundredths place |
55///
56/// Some functions deal with a *position* for the purpose of padding, truncating, or rounding a
57/// number. In these cases, the position sits between the corresponding magnitude of that position
58/// and the next lower significant digit.
59/// Illustration:
60///
61/// ```text
62/// Position:   2   0  -2
63/// Number:     |1|2.3|4|
64/// Position:     1  -1
65/// ```
66///
67/// Expected output of various operations, all with input "12.34":
68///
69/// | Operation                | Position  | Expected Result |
70/// |--------------------------|-----------|-----------------|
71/// | Truncate to tens         |         1 |   10            |
72/// | Truncate to tenths       |        -1 |   12.3          |
73/// | Pad to ten thousands     |         4 | 0012.34         |
74/// | Pad to ten thousandths   |        -4 |   12.3400       |
75///
76/// # Examples
77///
78/// ```
79/// use fixed_decimal::UnsignedDecimal;
80///
81/// let mut dec = UnsignedDecimal::from(250u32);
82/// assert_eq!("250", dec.to_string());
83///
84/// dec.multiply_pow10(-2);
85/// assert_eq!("2.50", dec.to_string());
86/// ```````
87#[derive(Debug, Clone, PartialEq)]
88pub struct UnsignedDecimal {
89    /// List of digits; digits\[0\] is the most significant.
90    ///
91    /// Invariants:
92    /// - Must not include leading or trailing zeros
93    /// - Length must not exceed (magnitude - lower_magnitude + 1)
94    // TODO: Consider using a nibble array
95    digits: SmallVec<[u8; 8]>,
96
97    /// Power of 10 of digits\[0\].
98    ///
99    /// Invariants:
100    /// - <= upper_magnitude
101    /// - >= lower_magnitude
102    magnitude: i16,
103
104    /// Power of 10 of the most significant digit, which may be zero.
105    ///
106    /// Invariants:
107    /// - >= 0
108    /// - >= magnitude
109    upper_magnitude: i16,
110
111    /// Power of 10 of the least significant digit, which may be zero.
112    ///
113    /// Invariants:
114    /// - <= 0
115    /// - <= magnitude
116    lower_magnitude: i16,
117}
118
119impl Default for UnsignedDecimal {
120    /// Returns a [`UnsignedDecimal`] representing zero.
121    fn default() -> Self {
122        Self {
123            digits: SmallVec::new(),
124            magnitude: 0,
125            upper_magnitude: 0,
126            lower_magnitude: 0,
127        }
128    }
129}
130
131macro_rules! impl_from_unsigned_integer_type {
132    ($utype: ident) => {
133        impl From<$utype> for UnsignedDecimal {
134            fn from(value: $utype) -> Self {
135                let int_iterator: IntIterator<$utype> = value.into();
136                Self::from_ascending(int_iterator).expect("All built-in integer types should fit")
137            }
138        }
139    };
140}
141
142impl_from_unsigned_integer_type!(usize);
143impl_from_unsigned_integer_type!(u128);
144impl_from_unsigned_integer_type!(u64);
145impl_from_unsigned_integer_type!(u32);
146impl_from_unsigned_integer_type!(u16);
147impl_from_unsigned_integer_type!(u8);
148
149impl UnsignedDecimal {
150    /// Initialize a [`UnsignedDecimal`] with an iterator of digits in ascending
151    /// order of magnitude, starting with the digit at magnitude 0.
152    ///
153    /// This method is not public; use `TryFrom::<isize>` instead.
154    pub(crate) fn from_ascending<T>(digits_iter: T) -> Result<Self, ParseError>
155    where
156        T: Iterator<Item = u8>,
157    {
158        // TODO: make X a usize generic to customize the size of this array
159        // https://github.com/rust-lang/rust/issues/44580
160        // NOTE: 39 is the size required for u128: ceil(log10(u128::MAX)) == 39.
161        const X: usize = 39;
162        // A temporary structure to allow the digits in the iterator to be reversed.
163        // The digits are inserted started from the end, and then a slice is copied
164        // into its final destination (result.digits).
165        let mut mem: [u8; X] = [0u8; X];
166        let mut trailing_zeros: usize = 0;
167        let mut i: usize = 0;
168        for (x, d) in digits_iter.enumerate() {
169            // Take only up to i16::MAX values so that we have enough capacity
170            if x > i16::MAX as usize {
171                return Err(ParseError::Limit);
172            }
173            // TODO: Should we check here that `d` is between 0 and 9?
174            // That should always be the case if IntIterator is used.
175            if i != 0 || d != 0 {
176                i += 1;
177                match X.checked_sub(i) {
178                    #[allow(clippy::indexing_slicing)] // X - i < X
179                    Some(v) => mem[v] = d,
180                    // This error should be obsolete after X is made generic
181                    None => return Err(ParseError::Limit),
182                }
183            } else {
184                trailing_zeros += 1;
185            }
186        }
187        let mut result: Self = Default::default();
188        if i != 0 {
189            let magnitude = trailing_zeros + i - 1;
190            debug_assert!(magnitude <= i16::MAX as usize);
191            result.magnitude = magnitude as i16;
192            result.upper_magnitude = result.magnitude;
193            debug_assert!(i <= X);
194            #[allow(clippy::indexing_slicing)] // X - i < X
195            result.digits.extend_from_slice(&mem[(X - i)..]);
196        }
197        #[cfg(debug_assertions)]
198        result.check_invariants();
199        Ok(result)
200    }
201
202    /// Gets the digit at the specified order of magnitude. Returns 0 if the magnitude is out of
203    /// range of the currently visible digits.
204    ///
205    /// # Examples
206    ///
207    /// ```
208    /// use fixed_decimal::UnsignedDecimal;
209    ///
210    /// let dec = UnsignedDecimal::from(945u32);
211    /// assert_eq!(0, dec.digit_at(-1));
212    /// assert_eq!(5, dec.digit_at(0));
213    /// assert_eq!(4, dec.digit_at(1));
214    /// assert_eq!(9, dec.digit_at(2));
215    /// assert_eq!(0, dec.digit_at(3));
216    /// ```
217    pub fn digit_at(&self, magnitude: i16) -> u8 {
218        if magnitude > self.magnitude {
219            0 // Leading zero
220        } else {
221            // The following line can't fail: magnitude <= self.magnitude, by
222            // the if statement above, and u16::MAX == i16::MAX - i16::MIN, and
223            // usize is asserted to be at least as big as u16.
224            let j = crate::ops::i16_abs_sub(self.magnitude, magnitude) as usize;
225            match self.digits.get(j) {
226                Some(v) => *v,
227                None => 0, // Trailing zero
228            }
229        }
230    }
231
232    /// Gets the digit at the specified order of next upper magnitude (magnitude + 1).
233    /// Returns 0 if the next upper magnitude is out of range of currently visible digits or
234    /// the magnitude is equal to `i16::MAX`.
235    fn digit_at_previous_position(&self, magnitude: i16) -> u8 {
236        if magnitude == i16::MAX {
237            0
238        } else {
239            self.digit_at(magnitude + 1)
240        }
241    }
242
243    /// Gets the digit at the specified order of next lower magnitude (magnitude - 1).
244    /// Returns 0 if the next lower magnitude is out of range of currently visible digits or the
245    /// magnitude is equal to `i16::MIN`.
246    fn digit_at_next_position(&self, magnitude: i16) -> u8 {
247        if magnitude == i16::MIN {
248            0
249        } else {
250            self.digit_at(magnitude - 1)
251        }
252    }
253
254    /// Returns the relative ordering of the digits after `magnitude` with respect to 5.
255    fn half_at_next_magnitude(&self, magnitude: i16) -> Ordering {
256        #[cfg(debug_assertions)] // Depends on having no trailing zeroes.
257        self.check_invariants();
258
259        match self.digit_at_next_position(magnitude).cmp(&5) {
260            // If the next digit is equal to 5, we can know if we're at exactly 5
261            // by comparing the next magnitude with the last nonzero magnitude of
262            // the number.
263            Ordering::Equal => match (magnitude - 1).cmp(&self.nonzero_magnitude_end()) {
264                Ordering::Greater => {
265                    // `magnitude - 1` has non-zero digits at its right,
266                    // meaning the number overall must be greater than 5.
267                    Ordering::Greater
268                }
269                Ordering::Equal => {
270                    // `magnitude - 1` is the last digit of the number,
271                    // meaning the number is exactly 5.
272                    Ordering::Equal
273                }
274                Ordering::Less => {
275                    debug_assert!(false, "digit `magnitude - 1` should not be zero");
276                    Ordering::Less
277                }
278            },
279            // If the next digit is either greater or less than 5,
280            // we know that the digits cannot sum to exactly 5.
281            ord => ord,
282        }
283    }
284
285    /// Returns the relative ordering of the digits from `magnitude` onwards
286    /// with respect to the half increment of `increment`.
287    fn half_increment_at_magnitude<R: IncrementLike>(
288        &self,
289        magnitude: i16,
290        increment: R,
291    ) -> Ordering {
292        #[cfg(debug_assertions)] // Depends on having no trailing zeroes.
293        self.check_invariants();
294
295        match Some(increment) {
296            x if x == R::MULTIPLES_OF_1 => self.half_at_next_magnitude(magnitude),
297            x if x == R::MULTIPLES_OF_2 => {
298                let current_digit = self.digit_at(magnitude);
299
300                // Equivalent to "if current_digit is odd".
301                if current_digit & 0x01 == 1 {
302                    match magnitude.cmp(&self.nonzero_magnitude_end()) {
303                        Ordering::Greater => {
304                            // `magnitude` has non-zero digits at its right,
305                            // meaning the number overall must be greater than
306                            // the half increment.
307                            Ordering::Greater
308                        }
309                        Ordering::Equal => {
310                            // `magnitude` is the last digit of the number,
311                            // meaning the number is exactly at a half increment.
312                            Ordering::Equal
313                        }
314                        Ordering::Less => {
315                            debug_assert!(false, "digit `magnitude` should not be zero");
316                            Ordering::Less
317                        }
318                    }
319                } else {
320                    // Even numbers are always below the half increment.
321                    Ordering::Less
322                }
323            }
324            x if x == R::MULTIPLES_OF_5 => {
325                let current_digit = self.digit_at(magnitude);
326                match (current_digit % 5).cmp(&2) {
327                    Ordering::Equal => {
328                        // Need to know if the number exceeds 2.5.
329                        self.half_at_next_magnitude(magnitude)
330                    }
331                    // If the next digit is either greater or less than the half increment,
332                    // we know that the digits cannot sum to exactly it.
333                    ord => ord,
334                }
335            }
336            x if x == R::MULTIPLES_OF_25 => {
337                let current_digit = self.digit_at(magnitude);
338                let prev_digit = self.digit_at_previous_position(magnitude);
339                let number = prev_digit * 10 + current_digit;
340
341                match (number % 25).cmp(&12) {
342                    Ordering::Equal => {
343                        // Need to know if the number exceeds 12.5.
344                        self.half_at_next_magnitude(magnitude)
345                    }
346                    // If the next digit is either greater or less than the half increment,
347                    // we know that the digits cannot sum to exactly it.
348                    ord => ord,
349                }
350            }
351            _ => {
352                debug_assert!(false, "increment should be 1, 2, 5, or 25");
353                Ordering::Equal
354            }
355        }
356    }
357
358    /// Checks if this number is already rounded to the specified magnitude and
359    /// increment.
360    fn is_rounded<R: IncrementLike>(&self, position: i16, increment: R) -> bool {
361        // The number is rounded if it's already zero, since zero is a multiple of
362        // all increments.
363        if self.is_zero() {
364            return true;
365        }
366
367        match Some(increment) {
368            x if x == R::MULTIPLES_OF_1 => {
369                // The number is rounded if `position` is the last digit
370                position <= self.nonzero_magnitude_end()
371            }
372            x if x == R::MULTIPLES_OF_2 => {
373                // The number is rounded if the digit at `position` is zero or
374                // the position is the last digit and the digit is a multiple of the increment
375                // already.
376                match position.cmp(&self.nonzero_magnitude_end()) {
377                    Ordering::Less => true,
378                    Ordering::Equal => self.digit_at(position) & 0x01 == 0,
379                    Ordering::Greater => false,
380                }
381            }
382            x if x == R::MULTIPLES_OF_5 => {
383                // The number is rounded if the digit at `position` is zero or
384                // the position is the last digit and the digit is a multiple of the increment
385                // already.
386                match position.cmp(&self.nonzero_magnitude_end()) {
387                    Ordering::Less => true,
388                    Ordering::Equal => self.digit_at(position) == 5,
389                    Ordering::Greater => false,
390                }
391            }
392            x if x == R::MULTIPLES_OF_25 => {
393                // The number is rounded if the digits at `position` and `position + 1` are
394                // both zeroes or if the last two digits are a multiple of the increment already.
395                match position.cmp(&self.nonzero_magnitude_end()) {
396                    Ordering::Less => {
397                        // `position` cannot be `i16::MAX` since it's less than
398                        // `self.nonzero_magnitude_end()`
399                        if position + 1 < self.nonzero_magnitude_end() {
400                            true
401                        } else {
402                            // position + 1 is equal to the last digit.
403                            // Need to exit if the number is 50.
404                            self.digit_at(position + 1) == 5
405                        }
406                    }
407                    Ordering::Equal => {
408                        let current_digit = self.digit_at(position);
409                        let prev_digit = self.digit_at_previous_position(position);
410                        let number = prev_digit * 10 + current_digit;
411
412                        matches!(number, 25 | 75)
413                    }
414                    Ordering::Greater => false,
415                }
416            }
417            _ => {
418                debug_assert!(false, "INCREMENT should be 1, 2, 5, or 25");
419                false
420            }
421        }
422    }
423
424    /// Gets the visible range of digit magnitudes, in ascending order of magnitude. Call `.rev()`
425    /// on the return value to get the range in descending order. Magnitude 0 is always included,
426    /// even if the number has leading or trailing zeros.
427    ///
428    /// # Examples
429    ///
430    /// ```
431    /// use fixed_decimal::UnsignedDecimal;
432    ///
433    /// let dec: UnsignedDecimal = "012.340".parse().expect("valid syntax");
434    /// assert_eq!(-3..=2, dec.magnitude_range());
435    /// ```
436    pub const fn magnitude_range(&self) -> RangeInclusive<i16> {
437        self.lower_magnitude..=self.upper_magnitude
438    }
439
440    /// Gets the magnitude of the largest nonzero digit. If the number is zero, 0 is returned.
441    ///
442    /// # Examples
443    ///
444    /// ```
445    /// use fixed_decimal::UnsignedDecimal;
446    ///
447    /// let dec: UnsignedDecimal = "012.340".parse().expect("valid syntax");
448    /// assert_eq!(1, dec.nonzero_magnitude_start());
449    ///
450    /// assert_eq!(0, UnsignedDecimal::from(0u32).nonzero_magnitude_start());
451    /// ```
452    pub fn nonzero_magnitude_start(&self) -> i16 {
453        self.magnitude
454    }
455
456    /// Gets the magnitude of the smallest nonzero digit. If the number is zero, 0 is returned.
457    ///
458    /// # Examples
459    ///
460    /// ```
461    /// use fixed_decimal::UnsignedDecimal;
462    ///
463    /// let dec: UnsignedDecimal = "012.340".parse().expect("valid syntax");
464    /// assert_eq!(-2, dec.nonzero_magnitude_end());
465    ///
466    /// assert_eq!(0, UnsignedDecimal::from(0u32).nonzero_magnitude_end());
467    /// ```
468    pub fn nonzero_magnitude_end(&self) -> i16 {
469        if self.is_zero() {
470            0
471        } else {
472            crate::ops::i16_sub_unsigned(self.magnitude, self.digits.len() as u16 - 1)
473        }
474    }
475
476    /// Returns whether the number has a numeric value of zero.
477    ///
478    /// # Examples
479    ///
480    /// ```
481    /// use fixed_decimal::UnsignedDecimal;
482    ///
483    /// let dec: UnsignedDecimal = "000.000".parse().expect("valid syntax");
484    /// assert!(dec.is_zero());
485    /// ```
486    #[inline]
487    pub fn is_zero(&self) -> bool {
488        self.digits.is_empty()
489    }
490
491    /// Clears all the fields and sets the number to zero.
492    pub(crate) fn clear(&mut self) {
493        self.upper_magnitude = 0;
494        self.lower_magnitude = 0;
495        self.magnitude = 0;
496        self.digits.clear();
497
498        #[cfg(debug_assertions)]
499        self.check_invariants();
500    }
501
502    /// Shift the digits of this number by a power of 10.
503    ///
504    /// Leading or trailing zeros may be added to keep the digit at magnitude 0 (the last digit
505    /// before the decimal separator) visible.
506    ///
507    /// NOTE: if the operation causes overflow, the number will be set to zero.
508    ///
509    /// # Examples
510    ///
511    /// ```
512    /// use fixed_decimal::UnsignedDecimal;
513    ///
514    /// let mut dec = UnsignedDecimal::from(42u32);
515    /// assert_eq!("42", dec.to_string());
516    ///
517    /// dec.multiply_pow10(3);
518    /// assert_eq!("42000", dec.to_string());
519    /// ```
520    pub fn multiply_pow10(&mut self, delta: i16) {
521        match delta.cmp(&0) {
522            Ordering::Greater => {
523                let upper_magnitude = self.upper_magnitude.checked_add(delta);
524                match upper_magnitude {
525                    Some(upper_magnitude) => {
526                        self.upper_magnitude = upper_magnitude;
527                        // If we get here, then the magnitude change is in-bounds.
528                        let lower_magnitude = self.lower_magnitude + delta;
529                        self.lower_magnitude = cmp::min(0, lower_magnitude);
530                    }
531                    None => {
532                        // there is an overflow
533                        self.clear();
534                    }
535                }
536            }
537            Ordering::Less => {
538                let lower_magnitude = self.lower_magnitude.checked_add(delta);
539                match lower_magnitude {
540                    Some(lower_magnitude) => {
541                        self.lower_magnitude = lower_magnitude;
542                        // If we get here, then the magnitude change is in-bounds.
543                        let upper_magnitude = self.upper_magnitude + delta;
544                        self.upper_magnitude = cmp::max(0, upper_magnitude);
545                    }
546                    None => {
547                        // there is an overflow
548                        self.clear();
549                    }
550                }
551            }
552            Ordering::Equal => {}
553        };
554        if !self.is_zero() {
555            self.magnitude += delta;
556        }
557        #[cfg(debug_assertions)]
558        self.check_invariants();
559    }
560
561    /// Returns this number with its digits shifted by a power of 10.
562    ///
563    /// Leading or trailing zeros may be added to keep the digit at magnitude 0 (the last digit
564    /// before the decimal separator) visible.
565    ///
566    /// NOTE: if the operation causes overflow, the returned number will be zero.
567    ///
568    /// # Examples
569    ///
570    /// ```
571    /// use fixed_decimal::UnsignedDecimal;
572    ///
573    /// let dec = UnsignedDecimal::from(42u32).multiplied_pow10(3);
574    /// assert_eq!("42000", dec.to_string());
575    /// ```
576    pub fn multiplied_pow10(mut self, delta: i16) -> Self {
577        self.multiply_pow10(delta);
578        self
579    }
580
581    /// Returns this number with its leading zeroes removed.
582    ///
583    /// # Examples
584    ///
585    /// ```
586    /// use fixed_decimal::UnsignedDecimal;
587    ///
588    /// let dec = UnsignedDecimal::from(123400u32)
589    ///     .multiplied_pow10(-4)
590    ///     .padded_start(4);
591    /// assert_eq!("0012.3400", dec.to_string());
592    ///
593    /// assert_eq!("12.3400", dec.trimmed_start().to_string());
594    /// ```
595    pub fn trimmed_start(mut self) -> Self {
596        self.trim_start();
597        self
598    }
599
600    /// Removes the leading zeroes of this number.
601    ///
602    /// # Examples
603    ///
604    /// ```
605    /// use fixed_decimal::UnsignedDecimal;
606    ///
607    /// let mut dec = UnsignedDecimal::from(123400u32)
608    ///     .multiplied_pow10(-4)
609    ///     .padded_start(4);
610    /// assert_eq!("0012.3400", dec.to_string());
611    ///
612    /// dec.trim_start();
613    /// assert_eq!("12.3400", dec.to_string());
614    /// ```
615    ///
616    /// There is no effect if the most significant digit has magnitude less than zero
617    ///
618    /// ```
619    /// # use fixed_decimal::UnsignedDecimal;
620    /// let mut dec = UnsignedDecimal::from(22u32).multiplied_pow10(-4);
621    /// assert_eq!("0.0022", dec.to_string());
622    ///
623    /// dec.trim_start();
624    /// assert_eq!("0.0022", dec.to_string());
625    /// ```
626    pub fn trim_start(&mut self) {
627        self.upper_magnitude = cmp::max(self.magnitude, 0);
628        #[cfg(debug_assertions)]
629        self.check_invariants();
630    }
631
632    /// Returns this number with its trailing zeros removed.
633    ///
634    /// # Examples
635    ///
636    /// ```
637    /// use fixed_decimal::UnsignedDecimal;
638    ///
639    /// let dec = UnsignedDecimal::from(123400u32)
640    ///     .multiplied_pow10(-4)
641    ///     .padded_start(4);
642    /// assert_eq!("0012.3400", dec.to_string());
643    ///
644    /// assert_eq!("0012.34", dec.trimmed_end().to_string());
645    /// ```
646    pub fn trimmed_end(mut self) -> Self {
647        self.trim_end();
648        self
649    }
650
651    /// Removes the trailing zeros of this number.
652    ///
653    /// # Examples
654    ///
655    /// ```
656    /// use fixed_decimal::UnsignedDecimal;
657    ///
658    /// let mut dec = UnsignedDecimal::from(123400u32)
659    ///     .multiplied_pow10(-4)
660    ///     .padded_start(4);
661    /// assert_eq!("0012.3400", dec.to_string());
662    ///
663    /// dec.trim_end();
664    /// assert_eq!("0012.34", dec.to_string());
665    /// ```
666    ///
667    /// There is no effect if the least significant digit has magnitude more than zero:
668    ///
669    /// ```
670    /// # use fixed_decimal::UnsignedDecimal;
671    /// let mut dec = UnsignedDecimal::from(2200u32);
672    /// assert_eq!("2200", dec.to_string());
673    ///
674    /// dec.trim_end();
675    /// assert_eq!("2200", dec.to_string());
676    /// ```
677    pub fn trim_end(&mut self) {
678        self.lower_magnitude = cmp::min(0, self.nonzero_magnitude_end());
679        #[cfg(debug_assertions)]
680        self.check_invariants();
681    }
682
683    /// Returns this number with its trailing zeros removed,
684    /// but only if the number is an integer
685    ///
686    /// # Examples
687    ///
688    /// ```
689    /// use fixed_decimal::UnsignedDecimal;
690    ///
691    /// let dec = UnsignedDecimal::from(12340000u32).multiplied_pow10(-2);
692    /// assert_eq!("123400.00", dec.to_string());
693    /// assert_eq!("123400", dec.trimmed_end_if_integer().to_string());
694    ///
695    /// // No effect if there are nonzero fractional digits:
696    /// let dec = UnsignedDecimal::from(123400u32)
697    ///     .multiplied_pow10(-4)
698    ///     .padded_start(4);
699    /// assert_eq!("0012.3400", dec.to_string());
700    /// assert_eq!("0012.3400", dec.trimmed_end_if_integer().to_string());
701    /// ```
702    pub fn trimmed_end_if_integer(mut self) -> Self {
703        self.trim_end_if_integer();
704        self
705    }
706
707    /// Removes the trailing zeros of this number,
708    /// but only if the number is an integer
709    ///
710    /// # Examples
711    ///
712    /// ```
713    /// use fixed_decimal::UnsignedDecimal;
714    ///
715    /// let mut dec = UnsignedDecimal::from(12340000u32).multiplied_pow10(-2);
716    /// assert_eq!("123400.00", dec.to_string());
717    ///
718    /// dec.trim_end_if_integer();
719    /// assert_eq!("123400", dec.to_string());
720    ///
721    /// // No effect on trailing zeros in the integer:
722    /// dec.trim_end_if_integer();
723    /// assert_eq!("123400", dec.to_string());
724    ///
725    /// // No effect if there are nonzero fractional digits:
726    /// dec.multiply_pow10(-4);
727    /// dec.pad_start(4);
728    /// assert_eq!("0012.3400", dec.to_string());
729    ///
730    /// dec.trim_end_if_integer();
731    /// assert_eq!("0012.3400", dec.to_string());
732    /// ```
733    pub fn trim_end_if_integer(&mut self) {
734        if self.nonzero_magnitude_end() >= 0 {
735            self.lower_magnitude = 0;
736        }
737        #[cfg(debug_assertions)]
738        self.check_invariants();
739    }
740
741    /// Returns this number padded with leading zeros on a particular position.
742    ///
743    /// Negative position numbers have no effect.
744    ///
745    /// Also see [`UnsignedDecimal::with_max_position()`].
746    ///
747    /// # Examples
748    ///
749    /// ```
750    /// use fixed_decimal::UnsignedDecimal;
751    ///
752    /// let mut dec = UnsignedDecimal::from(42u32);
753    /// assert_eq!("42", dec.to_string());
754    /// assert_eq!("0042", dec.clone().padded_start(4).to_string());
755    ///
756    /// assert_eq!("042", dec.clone().padded_start(3).to_string());
757    ///
758    /// assert_eq!("42", dec.clone().padded_start(2).to_string());
759    ///
760    /// assert_eq!("42", dec.clone().padded_start(1).to_string());
761    /// ```
762    pub fn padded_start(mut self, position: i16) -> Self {
763        self.pad_start(position);
764        self
765    }
766
767    /// Pads this number with leading zeros on a particular position.
768    ///
769    /// Negative position numbers have no effect.
770    ///
771    /// Also see [`UnsignedDecimal::set_max_position()`].
772    ///
773    /// # Examples
774    ///
775    /// ```
776    /// use fixed_decimal::UnsignedDecimal;
777    ///
778    /// let mut dec = UnsignedDecimal::from(42u32);
779    /// assert_eq!("42", dec.to_string());
780    ///
781    /// dec.pad_start(4);
782    /// assert_eq!("0042", dec.to_string());
783    ///
784    /// dec.pad_start(3);
785    /// assert_eq!("042", dec.to_string());
786    ///
787    /// dec.pad_start(2);
788    /// assert_eq!("42", dec.to_string());
789    ///
790    /// dec.pad_start(1);
791    /// assert_eq!("42", dec.to_string());
792    /// ```
793    pub fn pad_start(&mut self, position: i16) {
794        if position <= 0 {
795            return;
796        }
797        let mut magnitude = position - 1;
798        // Do not truncate nonzero digits
799        if magnitude <= self.magnitude {
800            magnitude = self.magnitude;
801        }
802        self.upper_magnitude = magnitude;
803        #[cfg(debug_assertions)]
804        self.check_invariants();
805    }
806
807    /// Returns this number padded with trailing zeros on a particular (negative) position.
808    /// Will truncate zeros if necessary, but will not truncate other digits.
809    ///
810    /// Positive position numbers have no effect.
811    ///
812    /// Also see [`UnsignedDecimal::trunced()`].
813    ///
814    /// # Examples
815    ///
816    /// ```
817    /// use fixed_decimal::UnsignedDecimal;
818    /// # use std::str::FromStr;
819    ///
820    /// let mut dec = UnsignedDecimal::from_str("123.456").unwrap();
821    /// assert_eq!("123.456", dec.to_string());
822    ///
823    /// assert_eq!("123.456", dec.clone().padded_end(-1).to_string());
824    ///
825    /// assert_eq!("123.456", dec.clone().padded_end(-2).to_string());
826    ///
827    /// assert_eq!("123.456000", dec.clone().padded_end(-6).to_string());
828    ///
829    /// assert_eq!("123.4560", dec.clone().padded_end(-4).to_string());
830    /// ```
831    pub fn padded_end(mut self, position: i16) -> Self {
832        self.pad_end(position);
833        self
834    }
835
836    /// Pads this number with trailing zeros on a particular (non-positive) position. Will truncate
837    /// trailing zeros if necessary, but will not truncate other digits.
838    ///
839    /// Positive position numbers have no effect.
840    ///
841    /// Also see [`UnsignedDecimal::trunc()`].
842    ///
843    /// # Examples
844    ///
845    /// ```
846    /// use fixed_decimal::UnsignedDecimal;
847    /// # use std::str::FromStr;
848    ///
849    /// let mut dec = UnsignedDecimal::from_str("123.456").unwrap();
850    /// assert_eq!("123.456", dec.to_string());
851    ///
852    /// dec.pad_end(-2);
853    /// assert_eq!("123.456", dec.to_string());
854    ///
855    /// dec.pad_end(-6);
856    /// assert_eq!("123.456000", dec.to_string());
857    ///
858    /// let mut dec = UnsignedDecimal::from_str("123.000").unwrap();
859    /// dec.pad_end(0);
860    /// assert_eq!("123", dec.to_string());
861    /// ```
862    pub fn pad_end(&mut self, position: i16) {
863        if position > 0 {
864            return;
865        }
866        let bottom_magnitude = self.nonzero_magnitude_end();
867        let mut magnitude = position;
868        // Do not truncate nonzero digits
869        if magnitude >= bottom_magnitude {
870            magnitude = bottom_magnitude;
871        }
872        self.lower_magnitude = magnitude;
873        #[cfg(debug_assertions)]
874        self.check_invariants();
875    }
876
877    /// Returns this number with the leading significant digits truncated to a particular position,
878    /// deleting digits if necessary.
879    ///
880    /// Also see [`UnsignedDecimal::padded_start()`].
881    ///
882    /// # Examples
883    ///
884    /// ```
885    /// use fixed_decimal::UnsignedDecimal;
886    ///
887    /// let mut dec = UnsignedDecimal::from(4235970u32).multiplied_pow10(-3);
888    /// assert_eq!("4235.970", dec.to_string());
889    ///
890    /// assert_eq!("04235.970", dec.clone().with_max_position(5).to_string());
891    ///
892    /// assert_eq!("35.970", dec.clone().with_max_position(2).to_string());
893    ///
894    /// assert_eq!("5.970", dec.clone().with_max_position(1).to_string());
895    ///
896    /// assert_eq!("0.970", dec.clone().with_max_position(0).to_string());
897    ///
898    /// assert_eq!("0.070", dec.clone().with_max_position(-1).to_string());
899    ///
900    /// assert_eq!("0.000", dec.clone().with_max_position(-2).to_string());
901    ///
902    /// assert_eq!("0.0000", dec.clone().with_max_position(-4).to_string());
903    /// ```
904    pub fn with_max_position(mut self, position: i16) -> Self {
905        self.set_max_position(position);
906        self
907    }
908
909    /// Truncates the leading significant digits of this number to a particular position, deleting
910    /// digits if necessary.
911    ///
912    /// Also see [`UnsignedDecimal::pad_start()`].
913    ///
914    /// # Examples
915    ///
916    /// ```
917    /// use fixed_decimal::UnsignedDecimal;
918    ///
919    /// let mut dec = UnsignedDecimal::from(4235970u32).multiplied_pow10(-3);
920    /// assert_eq!("4235.970", dec.to_string());
921    ///
922    /// dec.set_max_position(5);
923    /// assert_eq!("04235.970", dec.to_string());
924    ///
925    /// dec.set_max_position(2);
926    /// assert_eq!("35.970", dec.to_string());
927    ///
928    /// dec.set_max_position(1);
929    /// assert_eq!("5.970", dec.to_string());
930    ///
931    /// dec.set_max_position(0);
932    /// assert_eq!("0.970", dec.to_string());
933    ///
934    /// dec.set_max_position(-1);
935    /// assert_eq!("0.070", dec.to_string());
936    ///
937    /// dec.set_max_position(-2);
938    /// assert_eq!("0.000", dec.to_string());
939    ///
940    /// dec.set_max_position(-4);
941    /// assert_eq!("0.0000", dec.to_string());
942    /// ```
943    pub fn set_max_position(&mut self, position: i16) {
944        self.lower_magnitude = cmp::min(self.lower_magnitude, position);
945        self.upper_magnitude = if position <= 0 { 0 } else { position - 1 };
946        if position <= self.nonzero_magnitude_end() {
947            self.digits.clear();
948            self.magnitude = 0;
949            #[cfg(debug_assertions)]
950            self.check_invariants();
951            return;
952        }
953        let magnitude = position - 1;
954        if self.magnitude >= magnitude {
955            let cut = crate::ops::i16_abs_sub(self.magnitude, magnitude) as usize;
956            let _ = self.digits.drain(0..cut).count();
957            // Count number of leading zeroes
958            let extra_zeroes = self.digits.iter().position(|x| *x != 0).unwrap_or(0);
959            let _ = self.digits.drain(0..extra_zeroes).count();
960            debug_assert!(!self.digits.is_empty());
961            self.magnitude = crate::ops::i16_sub_unsigned(magnitude, extra_zeroes as u16);
962        }
963        #[cfg(debug_assertions)]
964        self.check_invariants();
965    }
966
967    /// Rounds this number at a particular digit position.
968    ///
969    /// This uses half to even rounding, which rounds to the nearest integer and resolves ties by
970    /// selecting the nearest even integer to the original value.
971    ///
972    /// # Examples
973    ///
974    /// ```
975    /// use fixed_decimal::UnsignedDecimal;
976    /// # use std::str::FromStr;
977    ///
978    /// let mut dec = UnsignedDecimal::from_str("0.4").unwrap();
979    /// dec.round(0);
980    /// assert_eq!("0", dec.to_string());
981    /// let mut dec = UnsignedDecimal::from_str("0.5").unwrap();
982    /// dec.round(0);
983    /// assert_eq!("0", dec.to_string());
984    /// let mut dec = UnsignedDecimal::from_str("0.6").unwrap();
985    /// dec.round(0);
986    /// assert_eq!("1", dec.to_string());
987    /// let mut dec = UnsignedDecimal::from_str("1.5").unwrap();
988    /// dec.round(0);
989    /// assert_eq!("2", dec.to_string());
990    /// ```
991    pub fn round(&mut self, position: i16) {
992        self.half_even_to_increment_internal(position, NoIncrement)
993    }
994
995    /// Returns this number rounded at a particular digit position.
996    ///
997    /// This uses half to even rounding by default, which rounds to the nearest integer and
998    /// resolves ties by selecting the nearest even integer to the original value.
999    ///
1000    /// # Examples
1001    ///
1002    /// ```
1003    /// use fixed_decimal::UnsignedDecimal;
1004    /// # use std::str::FromStr;
1005    ///
1006    /// let mut dec = UnsignedDecimal::from_str("0.4").unwrap();
1007    /// assert_eq!("0", dec.rounded(0).to_string());
1008    /// let mut dec = UnsignedDecimal::from_str("0.5").unwrap();
1009    /// assert_eq!("0", dec.rounded(0).to_string());
1010    /// let mut dec = UnsignedDecimal::from_str("0.6").unwrap();
1011    /// assert_eq!("1", dec.rounded(0).to_string());
1012    /// let mut dec = UnsignedDecimal::from_str("1.5").unwrap();
1013    /// assert_eq!("2", dec.rounded(0).to_string());
1014    /// ```
1015    pub fn rounded(mut self, position: i16) -> Self {
1016        self.round(position);
1017        self
1018    }
1019
1020    /// Rounds this number away from zero at a particular digit position.
1021    ///
1022    /// # Examples
1023    ///
1024    /// ```
1025    /// use fixed_decimal::UnsignedDecimal;
1026    /// # use std::str::FromStr;
1027    ///
1028    /// let mut dec = UnsignedDecimal::from_str("0.4").unwrap();
1029    /// dec.expand(0);
1030    /// assert_eq!("1", dec.to_string());
1031    /// let mut dec = UnsignedDecimal::from_str("0.5").unwrap();
1032    /// dec.expand(0);
1033    /// assert_eq!("1", dec.to_string());
1034    /// let mut dec = UnsignedDecimal::from_str("0.6").unwrap();
1035    /// dec.expand(0);
1036    /// assert_eq!("1", dec.to_string());
1037    /// let mut dec = UnsignedDecimal::from_str("1.5").unwrap();
1038    /// dec.expand(0);
1039    /// assert_eq!("2", dec.to_string());
1040    /// ```
1041    #[inline(never)]
1042    pub fn expand(&mut self, position: i16) {
1043        self.expand_to_increment_internal(position, NoIncrement)
1044    }
1045
1046    /// Returns this number rounded away from zero at a particular digit position.
1047    ///
1048    /// # Examples
1049    ///
1050    /// ```
1051    /// use fixed_decimal::UnsignedDecimal;
1052    /// # use std::str::FromStr;
1053    ///
1054    /// let dec = UnsignedDecimal::from_str("0.4").unwrap();
1055    /// assert_eq!("1", dec.expanded(0).to_string());
1056    /// let dec = UnsignedDecimal::from_str("0.5").unwrap();
1057    /// assert_eq!("1", dec.expanded(0).to_string());
1058    /// let dec = UnsignedDecimal::from_str("0.6").unwrap();
1059    /// assert_eq!("1", dec.expanded(0).to_string());
1060    /// let dec = UnsignedDecimal::from_str("1.5").unwrap();
1061    /// assert_eq!("2", dec.expanded(0).to_string());
1062    /// ```
1063    pub fn expanded(mut self, position: i16) -> Self {
1064        self.expand(position);
1065        self
1066    }
1067
1068    /// Rounds this number towards zero at a particular digit position.
1069    ///
1070    /// Also see [`UnsignedDecimal::pad_end()`].
1071    ///
1072    /// # Examples
1073    ///
1074    /// ```
1075    /// use fixed_decimal::UnsignedDecimal;
1076    /// # use std::str::FromStr;
1077    ///
1078    /// let mut dec = UnsignedDecimal::from_str("0.4").unwrap();
1079    /// dec.trunc(0);
1080    /// assert_eq!("0", dec.to_string());
1081    /// let mut dec = UnsignedDecimal::from_str("0.5").unwrap();
1082    /// dec.trunc(0);
1083    /// assert_eq!("0", dec.to_string());
1084    /// let mut dec = UnsignedDecimal::from_str("0.6").unwrap();
1085    /// dec.trunc(0);
1086    /// assert_eq!("0", dec.to_string());
1087    /// let mut dec = UnsignedDecimal::from_str("1.5").unwrap();
1088    /// dec.trunc(0);
1089    /// assert_eq!("1", dec.to_string());
1090    /// ```
1091    #[inline(never)]
1092    pub fn trunc(&mut self, position: i16) {
1093        self.trunc_to_increment_internal(position, NoIncrement)
1094    }
1095
1096    /// Returns this number rounded towards zero at a particular digit position.
1097    ///
1098    /// Also see [`UnsignedDecimal::padded_end()`].
1099    ///
1100    /// # Examples
1101    ///
1102    /// ```
1103    /// use fixed_decimal::UnsignedDecimal;
1104    /// # use std::str::FromStr;
1105    ///
1106    /// let dec = UnsignedDecimal::from_str("0.4").unwrap();
1107    /// assert_eq!("0", dec.trunced(0).to_string());
1108    /// let dec = UnsignedDecimal::from_str("0.5").unwrap();
1109    /// assert_eq!("0", dec.trunced(0).to_string());
1110    /// let dec = UnsignedDecimal::from_str("0.6").unwrap();
1111    /// assert_eq!("0", dec.trunced(0).to_string());
1112    /// let dec = UnsignedDecimal::from_str("1.5").unwrap();
1113    /// assert_eq!("1", dec.trunced(0).to_string());
1114    /// ```
1115    pub fn trunced(mut self, position: i16) -> Self {
1116        self.trunc(position);
1117        self
1118    }
1119
1120    /// Rounds this number at a particular digit position, using the specified rounding mode.
1121    ///
1122    /// # Examples
1123    ///
1124    /// ```
1125    /// use fixed_decimal::{UnsignedDecimal, UnsignedRoundingMode};
1126    /// # use std::str::FromStr;
1127    ///
1128    /// let mut dec = UnsignedDecimal::from_str("5.455").unwrap();
1129    /// dec.round_with_mode(-2, UnsignedRoundingMode::HalfExpand);
1130    /// assert_eq!("5.46", dec.to_string());
1131    /// let mut dec = UnsignedDecimal::from_str("9.75").unwrap();
1132    /// dec.round_with_mode(-1, UnsignedRoundingMode::HalfEven);
1133    /// assert_eq!("9.8", dec.to_string());
1134    /// ```
1135    pub fn round_with_mode(&mut self, position: i16, mode: UnsignedRoundingMode) {
1136        match mode {
1137            UnsignedRoundingMode::Expand => {
1138                self.expand_to_increment_internal(position, NoIncrement)
1139            }
1140            UnsignedRoundingMode::Trunc => self.trunc_to_increment_internal(position, NoIncrement),
1141            UnsignedRoundingMode::HalfExpand => {
1142                self.half_expand_to_increment_internal(position, NoIncrement)
1143            }
1144            UnsignedRoundingMode::HalfTrunc => {
1145                self.half_trunc_to_increment_internal(position, NoIncrement)
1146            }
1147            UnsignedRoundingMode::HalfEven => {
1148                self.half_even_to_increment_internal(position, NoIncrement)
1149            }
1150        }
1151    }
1152
1153    /// Returns this number rounded at a particular digit position, using the specified rounding mode.
1154    ///
1155    /// # Examples
1156    ///
1157    /// ```
1158    /// use fixed_decimal::{UnsignedDecimal, UnsignedRoundingMode};
1159    /// # use std::str::FromStr;
1160    ///
1161    /// let mut dec = UnsignedDecimal::from_str("5.455").unwrap();
1162    /// assert_eq!(
1163    ///     "5.46",
1164    ///     dec.rounded_with_mode(-2, UnsignedRoundingMode::HalfExpand)
1165    ///         .to_string()
1166    /// );
1167    /// let mut dec = UnsignedDecimal::from_str("9.75").unwrap();
1168    /// assert_eq!(
1169    ///     "9.8",
1170    ///     dec.rounded_with_mode(-1, UnsignedRoundingMode::HalfEven)
1171    ///         .to_string()
1172    /// );
1173    /// ```
1174    pub fn rounded_with_mode(mut self, position: i16, mode: UnsignedRoundingMode) -> Self {
1175        self.round_with_mode(position, mode);
1176        self
1177    }
1178
1179    /// Rounds this number at a particular digit position and increment, using the specified rounding mode.
1180    ///
1181    /// # Examples
1182    ///
1183    /// ```
1184    /// use fixed_decimal::{
1185    ///     RoundingIncrement, UnsignedDecimal, UnsignedRoundingMode,
1186    /// };
1187    /// # use std::str::FromStr;
1188    ///
1189    /// let mut dec = UnsignedDecimal::from_str("5.455").unwrap();
1190    /// dec.round_with_mode_and_increment(
1191    ///     -2,
1192    ///     UnsignedRoundingMode::HalfExpand,
1193    ///     RoundingIncrement::MultiplesOf5,
1194    /// );
1195    /// assert_eq!("5.45", dec.to_string());
1196    ///
1197    /// let mut dec = UnsignedDecimal::from_str("9.75").unwrap();
1198    /// dec.round_with_mode_and_increment(
1199    ///     -1,
1200    ///     UnsignedRoundingMode::HalfEven,
1201    ///     RoundingIncrement::MultiplesOf5,
1202    /// );
1203    /// assert_eq!("10.0", dec.to_string());
1204    /// ```
1205    pub fn round_with_mode_and_increment(
1206        &mut self,
1207        position: i16,
1208        mode: UnsignedRoundingMode,
1209        increment: RoundingIncrement,
1210    ) {
1211        match mode {
1212            UnsignedRoundingMode::Expand => self.expand_to_increment_internal(position, increment),
1213            UnsignedRoundingMode::Trunc => self.trunc_to_increment_internal(position, increment),
1214            UnsignedRoundingMode::HalfExpand => {
1215                self.half_expand_to_increment_internal(position, increment)
1216            }
1217            UnsignedRoundingMode::HalfTrunc => {
1218                self.half_trunc_to_increment_internal(position, increment)
1219            }
1220            UnsignedRoundingMode::HalfEven => {
1221                self.half_even_to_increment_internal(position, increment)
1222            }
1223        }
1224    }
1225
1226    /// Returns this number rounded at a particular digit position and increment, using the specified rounding mode.
1227    ///
1228    /// # Examples
1229    ///
1230    /// ```
1231    /// use fixed_decimal::{
1232    ///     RoundingIncrement, UnsignedDecimal, UnsignedRoundingMode,
1233    /// };
1234    /// # use std::str::FromStr;
1235    ///
1236    /// let mut dec = UnsignedDecimal::from_str("5.455").unwrap();
1237    /// assert_eq!(
1238    ///     "5.45",
1239    ///     dec.rounded_with_mode_and_increment(
1240    ///         -2,
1241    ///         UnsignedRoundingMode::HalfExpand,
1242    ///         RoundingIncrement::MultiplesOf5
1243    ///     )
1244    ///     .to_string()
1245    /// );
1246    ///
1247    /// let mut dec = UnsignedDecimal::from_str("9.75").unwrap();
1248    /// assert_eq!(
1249    ///     "10.0",
1250    ///     dec.rounded_with_mode_and_increment(
1251    ///         -1,
1252    ///         UnsignedRoundingMode::HalfEven,
1253    ///         RoundingIncrement::MultiplesOf5
1254    ///     )
1255    ///     .to_string()
1256    /// );
1257    /// ```
1258    pub fn rounded_with_mode_and_increment(
1259        mut self,
1260        position: i16,
1261        mode: UnsignedRoundingMode,
1262        increment: RoundingIncrement,
1263    ) -> Self {
1264        self.round_with_mode_and_increment(position, mode, increment);
1265        self
1266    }
1267
1268    pub(crate) fn expand_to_increment_internal<R: IncrementLike>(
1269        &mut self,
1270        position: i16,
1271        inner_increment: R,
1272    ) {
1273        /// Modifies `number` to signal that an overflow happened.
1274        fn overflow(number: &mut UnsignedDecimal) {
1275            // TODO(#2297): Decide on behavior here
1276            number.digits.clear();
1277            number.magnitude = 0;
1278            #[cfg(debug_assertions)]
1279            number.check_invariants();
1280        }
1281
1282        let increment = Some(inner_increment);
1283
1284        // 1. Set upper and lower magnitude
1285        self.lower_magnitude = cmp::min(position, 0);
1286
1287        match position.cmp(&i16::MIN) {
1288            // Don't return if the increment is not one, because we
1289            // also need to round to the next increment if necessary.
1290            Ordering::Equal if increment == R::MULTIPLES_OF_1 => {
1291                // Nothing more to do
1292                #[cfg(debug_assertions)]
1293                self.check_invariants();
1294                return;
1295            }
1296            Ordering::Greater => {
1297                self.upper_magnitude = cmp::max(self.upper_magnitude, position - 1);
1298            }
1299            _ => {
1300                // Ordering::Less is unreachable, and Ordering::Equal needs to apply roundings
1301                // when the increment is not equal to 1.
1302                // We don't override `self.upper_magnitude` because `self.upper_magnitude` is
1303                // always equal or bigger than `i16::MIN`.
1304            }
1305        }
1306
1307        // 2. If the number is already rounded, exit early.
1308        if self.is_rounded(position, inner_increment) {
1309            #[cfg(debug_assertions)]
1310            self.check_invariants();
1311            return;
1312        }
1313
1314        // 3. If the rounding position is *in the middle* of the nonzero digits
1315        if position <= self.magnitude {
1316            // 3a. Calculate the number of digits to retain and remove the rest
1317            let digits_to_retain = crate::ops::i16_abs_sub(self.magnitude, position) + 1;
1318            self.digits.truncate(digits_to_retain as usize);
1319
1320            // 3b. Handle the last digit considering the increment.
1321            let iter = match increment {
1322                x if x == R::MULTIPLES_OF_1 => {
1323                    // Can just execute the algorithm normally.
1324
1325                    self.digits.iter_mut().rev().enumerate()
1326                }
1327                x if x == R::MULTIPLES_OF_2 => {
1328                    let mut iter = self.digits.iter_mut().rev().enumerate();
1329
1330                    // Must round the last digit to the next increment.
1331                    let Some((_, digit)) = iter.next() else {
1332                        debug_assert!(false, "`self.digits` should have at least a digit");
1333                        return;
1334                    };
1335
1336                    // Equivalent to (n + 2 / 2) * 2, which expands to the next
1337                    // multiple of two
1338                    *digit = (*digit + 2) & 0xFE;
1339
1340                    if *digit < 10 {
1341                        // Early returns if the expansion didn't generate a remainder.
1342                        #[cfg(debug_assertions)]
1343                        self.check_invariants();
1344                        return;
1345                    }
1346
1347                    iter
1348                }
1349                x if x == R::MULTIPLES_OF_5 => {
1350                    let mut iter = self.digits.iter_mut().rev().enumerate();
1351
1352                    // Must round the last digit to the next increment.
1353                    let Some((_, digit)) = iter.next() else {
1354                        debug_assert!(false, "`self.digits` should have at least a digit");
1355                        return;
1356                    };
1357
1358                    if *digit < 5 {
1359                        *digit = 5;
1360
1361                        // Early return since the expansion didn't generate a remainder.
1362                        #[cfg(debug_assertions)]
1363                        self.check_invariants();
1364                        return;
1365                    }
1366
1367                    *digit = 10;
1368
1369                    iter
1370                }
1371                x if x == R::MULTIPLES_OF_25 => {
1372                    // Extend the digits to have the correct
1373                    // number of trailing zeroes.
1374                    self.digits.resize(digits_to_retain as usize, 0);
1375
1376                    let Some((last_digit, digits)) = self.digits.split_last_mut() else {
1377                        debug_assert!(false, "`self.digits` should have at least a digit");
1378                        return;
1379                    };
1380
1381                    let Some((second_last_digit, _)) = digits.split_last_mut() else {
1382                        // The number has no other digits aside from the last.
1383                        // We need to manually increment the number to 25
1384
1385                        if self.magnitude == i16::MAX {
1386                            overflow(self);
1387                            return;
1388                        }
1389
1390                        self.digits.clear();
1391                        self.digits.extend_from_slice(&[2, 5]);
1392                        self.magnitude += 1;
1393                        self.upper_magnitude = cmp::max(self.upper_magnitude, self.magnitude);
1394
1395                        #[cfg(debug_assertions)]
1396                        self.check_invariants();
1397                        return;
1398                    };
1399
1400                    let number = *second_last_digit * 10 + *last_digit;
1401
1402                    if number < 75 {
1403                        // We can return directly if the number won't expand
1404                        // to 100.
1405                        if number < 25 {
1406                            *second_last_digit = 2;
1407                            *last_digit = 5;
1408                        } else if number < 50 {
1409                            *second_last_digit = 5;
1410                            self.digits.pop();
1411                        } else {
1412                            *second_last_digit = 7;
1413                            *last_digit = 5;
1414                        }
1415
1416                        #[cfg(debug_assertions)]
1417                        self.check_invariants();
1418                        return;
1419                    }
1420
1421                    // The number reached 100. Continue the algorithm but with the
1422                    // last two digits removed from the iterator.
1423
1424                    *second_last_digit = 10;
1425                    *last_digit = 10;
1426
1427                    let mut iter = self.digits.iter_mut().rev().enumerate();
1428
1429                    // Remove the last two items that were already handled.
1430                    iter.next();
1431                    iter.next();
1432
1433                    iter
1434                }
1435                _ => {
1436                    debug_assert!(false, "INCREMENT should be 1, 2, 5, or 25");
1437                    return;
1438                }
1439            };
1440
1441            // 3b. Increment the rightmost remaining digit since we are rounding up; this might
1442            // require bubbling the addition to higher magnitudes, like 199 + 1 = 200
1443            for (zero_count, digit) in iter {
1444                *digit += 1;
1445                if *digit < 10 {
1446                    self.digits.truncate(self.digits.len() - zero_count);
1447                    #[cfg(debug_assertions)]
1448                    self.check_invariants();
1449                    return;
1450                }
1451            }
1452
1453            // 3c. If we get here, the mantissa is fully saturated.
1454            // Clear the saturated mantissa and replace everything with a single 1.
1455
1456            if self.magnitude == i16::MAX {
1457                overflow(self);
1458                return;
1459            }
1460
1461            self.digits.clear();
1462            self.digits.push(1);
1463
1464            self.magnitude += 1;
1465            self.upper_magnitude = cmp::max(self.upper_magnitude, self.magnitude);
1466
1467            #[cfg(debug_assertions)]
1468            self.check_invariants();
1469            return;
1470        }
1471
1472        // 4. If the rounding position is *above* the leftmost nonzero digit,
1473        // set the value to the next increment at the appropriate position.
1474
1475        // Check if we have enough available spaces to push a `25` at the start.
1476        if increment == R::MULTIPLES_OF_25 && position == i16::MAX {
1477            // Need an extra digit to push a 25, which we don't have.
1478            overflow(self);
1479            return;
1480        }
1481
1482        self.digits.clear();
1483
1484        // We need to push the next multiple of the increment,
1485        // and we also need to adjust the magnitude to the
1486        // new upper magnitude.
1487        let increment_digits = match increment {
1488            x if x == R::MULTIPLES_OF_1 => [1].as_slice(),
1489            x if x == R::MULTIPLES_OF_2 => [2].as_slice(),
1490            x if x == R::MULTIPLES_OF_5 => [5].as_slice(),
1491            x if x == R::MULTIPLES_OF_25 => [2, 5].as_slice(),
1492            _ => {
1493                debug_assert!(false, "INCREMENT should be 1, 2, 5, or 25");
1494                return;
1495            }
1496        };
1497        self.digits.extend_from_slice(increment_digits);
1498
1499        // Could also be derived from `increment_digits.len() - 1`, but it makes
1500        // the logic a bit harder to follow.
1501        self.magnitude = if increment == R::MULTIPLES_OF_25 {
1502            position + 1
1503        } else {
1504            position
1505        };
1506
1507        self.upper_magnitude = cmp::max(self.upper_magnitude, self.magnitude);
1508
1509        #[cfg(debug_assertions)]
1510        self.check_invariants();
1511    }
1512
1513    pub(crate) fn trunc_to_increment_internal<R: IncrementLike>(
1514        &mut self,
1515        position: i16,
1516        inner_increment: R,
1517    ) {
1518        let increment = Some(inner_increment);
1519
1520        // 1. Set upper and lower magnitude
1521        self.lower_magnitude = cmp::min(position, 0);
1522
1523        match position.cmp(&i16::MIN) {
1524            // Don't return if the increment is not one, because we
1525            // also need to round to the next increment if necessary.
1526            Ordering::Equal if increment == R::MULTIPLES_OF_1 => {
1527                // Nothing more to do
1528                #[cfg(debug_assertions)]
1529                self.check_invariants();
1530                return;
1531            }
1532            Ordering::Greater => {
1533                self.upper_magnitude = cmp::max(self.upper_magnitude, position - 1);
1534            }
1535            _ => {
1536                // Ordering::Less is unreachable, and Ordering::Equal needs to apply roundings
1537                // when the increment is not equal to 1.
1538                // We don't override `self.upper_magnitude` because `self.upper_magnitude` is
1539                // always equal or bigger than `i16::MIN`.
1540            }
1541        }
1542
1543        // 2. If the number is already rounded, exit early.
1544        if self.is_rounded(position, inner_increment) {
1545            #[cfg(debug_assertions)]
1546            self.check_invariants();
1547            return;
1548        }
1549
1550        // 3. If the rounding position is *in the middle* of the nonzero digits
1551        if position <= self.magnitude {
1552            // 3a. Calculate the number of digits to retain and remove the rest
1553            let digits_to_retain = crate::ops::i16_abs_sub(self.magnitude, position) + 1;
1554            self.digits.truncate(digits_to_retain as usize);
1555
1556            // 3b. Truncate to the previous multiple.
1557            match increment {
1558                x if x == R::MULTIPLES_OF_1 => {
1559                    // No need to do more work, trailing zeroes are removed below.
1560                }
1561                x if x == R::MULTIPLES_OF_2 => {
1562                    let Some(last_digit) = self.digits.last_mut() else {
1563                        debug_assert!(false, "`self.digits` should have at least a digit");
1564                        return;
1565                    };
1566
1567                    // Equivalent to (n / 2) * 2, which truncates to the previous
1568                    // multiple of two
1569                    *last_digit &= 0xFE;
1570                }
1571                x if x == R::MULTIPLES_OF_5 => {
1572                    let Some(last_digit) = self.digits.last_mut() else {
1573                        debug_assert!(false, "`self.digits` should have at least a digit");
1574                        return;
1575                    };
1576
1577                    *last_digit = if *last_digit < 5 { 0 } else { 5 };
1578                }
1579                x if x == R::MULTIPLES_OF_25 => {
1580                    // Extend with zeroes to have the correct trailing digits.
1581                    self.digits.resize(digits_to_retain as usize, 0);
1582
1583                    let Some((last_digit, digits)) = self.digits.split_last_mut() else {
1584                        debug_assert!(false, "`self.digits` should have at least a digit");
1585                        return;
1586                    };
1587
1588                    if let Some(second_last_digit) = digits.last_mut() {
1589                        let number = *second_last_digit * 10 + *last_digit;
1590
1591                        // Trailing zeroes will be removed below. We can defer
1592                        // the deletion to there.
1593                        (*second_last_digit, *last_digit) = if number < 25 {
1594                            (0, 0)
1595                        } else if number < 50 {
1596                            (2, 5)
1597                        } else if number < 75 {
1598                            (5, 0)
1599                        } else {
1600                            (7, 5)
1601                        };
1602                    } else {
1603                        // The number has no other digits aside from the last,
1604                        // making it strictly less than 25.
1605                        *last_digit = 0;
1606                    };
1607                }
1608                _ => {
1609                    debug_assert!(false, "INCREMENT should be 1, 2, 5, or 25");
1610                    return;
1611                }
1612            }
1613
1614            // 3c. Handle the case where `digits` has trailing zeroes after
1615            // truncating to the previous multiple.
1616            let position_last_nonzero_digit = self
1617                .digits
1618                .iter()
1619                .rposition(|x| *x != 0)
1620                .map(|x| x + 1)
1621                .unwrap_or(0);
1622            self.digits.truncate(position_last_nonzero_digit);
1623
1624            // 3d. If `digits` had only trailing zeroes after truncating,
1625            // reset to zero.
1626            if self.digits.is_empty() {
1627                self.magnitude = 0;
1628            }
1629        } else {
1630            // 4. If the rounding position is *above* the leftmost nonzero
1631            // digit, set to zero
1632            self.digits.clear();
1633            self.magnitude = 0;
1634        }
1635
1636        #[cfg(debug_assertions)]
1637        self.check_invariants();
1638    }
1639
1640    pub(crate) fn half_even_to_increment_internal<R: IncrementLike>(
1641        &mut self,
1642        position: i16,
1643        increment: R,
1644    ) {
1645        let should_expand = match self.half_increment_at_magnitude(position, increment) {
1646            Ordering::Greater => true,
1647            Ordering::Less => false,
1648            Ordering::Equal => match Some(increment) {
1649                x if x == R::MULTIPLES_OF_1 => {
1650                    // Expand if odd, truncate if even.
1651                    self.digit_at(position) & 0x01 == 1
1652                }
1653                x if x == R::MULTIPLES_OF_2 => {
1654                    let current_digit = self.digit_at(position);
1655                    let previous_digit = self.digit_at_previous_position(position);
1656                    let full = previous_digit * 10 + current_digit;
1657
1658                    // This essentially expands to the "even" increments,
1659                    // or the increments that are in the even places on the
1660                    // rounding range: [0, 4, 8, 12, 16, 20, ...].
1661                    // Equivalent to `(full / 2) is odd`.
1662                    //
1663                    // Examples:
1664                    // - 37 should truncate, since 37 % 20 = 17, which truncates to 16.
1665                    //   37 / 2 = 18, which is even.
1666                    // - 83 should expand, since 83 % 20 = 3, which expands to 4.
1667                    //   83 / 2 = 41, which is odd.
1668                    (full >> 1) & 0x01 == 1
1669                }
1670                x if x == R::MULTIPLES_OF_5 => {
1671                    // Expand 7.5 to 10 and truncate 2.5 to 0.
1672                    self.digit_at(position) == 7
1673                }
1674                x if x == R::MULTIPLES_OF_25 => {
1675                    let current_digit = self.digit_at(position);
1676                    let prev_digit = self.digit_at_previous_position(position);
1677                    let full_number = prev_digit * 10 + current_digit;
1678
1679                    // Expand `37.5` to 50 and `87.5` to 100.
1680                    // Truncate `12.5` to 0 and `62.5` to 50.
1681                    full_number == 37 || full_number == 87
1682                }
1683                _ => {
1684                    debug_assert!(false, "INCREMENT should be 1, 2, 5, or 25");
1685                    return;
1686                }
1687            },
1688        };
1689
1690        if should_expand {
1691            self.expand_to_increment_internal(position, increment);
1692        } else {
1693            self.trunc_to_increment_internal(position, increment);
1694        }
1695    }
1696
1697    pub(crate) fn half_expand_to_increment_internal<R: IncrementLike>(
1698        &mut self,
1699        position: i16,
1700        increment: R,
1701    ) {
1702        // Only truncate if the rounding position is strictly less than the half increment.
1703        // At the half increment, `half_expand` always expands.
1704        let should_trunc = self.half_increment_at_magnitude(position, increment) == Ordering::Less;
1705
1706        if should_trunc {
1707            self.trunc_to_increment_internal(position, increment);
1708        } else {
1709            self.expand_to_increment_internal(position, increment);
1710        }
1711    }
1712
1713    pub(crate) fn half_trunc_to_increment_internal<R: IncrementLike>(
1714        &mut self,
1715        position: i16,
1716        increment: R,
1717    ) {
1718        // Only expand if the rounding position is strictly greater than the half increment.
1719        // At the half increment, `half_trunc` always truncates.
1720        let should_expand =
1721            self.half_increment_at_magnitude(position, increment) == Ordering::Greater;
1722
1723        if should_expand {
1724            self.expand_to_increment_internal(position, increment);
1725        } else {
1726            self.trunc_to_increment_internal(position, increment);
1727        }
1728    }
1729
1730    /// Concatenate another [`UnsignedDecimal`] into the end of this [`UnsignedDecimal`].
1731    ///
1732    /// All nonzero digits in `other` must have lower magnitude than nonzero digits in `self`.
1733    /// If the two decimals represent overlapping ranges of magnitudes, an `Err` is returned,
1734    /// containing (self, other).
1735    ///
1736    /// The magnitude range of `self` will be increased if `other` covers a larger range.
1737    ///
1738    /// # Examples
1739    ///
1740    /// ```
1741    /// use fixed_decimal::UnsignedDecimal;
1742    ///
1743    /// let integer = UnsignedDecimal::from(123u32);
1744    /// let fraction = UnsignedDecimal::from(456u32).multiplied_pow10(-3);
1745    ///
1746    /// let result = integer.concatenated_end(fraction).expect("nonoverlapping");
1747    ///
1748    /// assert_eq!("123.456", result.to_string());
1749    /// ```
1750    pub fn concatenated_end(
1751        mut self,
1752        other: UnsignedDecimal,
1753    ) -> Result<Self, (UnsignedDecimal, UnsignedDecimal)> {
1754        match self.concatenate_end(other) {
1755            Ok(()) => Ok(self),
1756            Err(err) => Err((self, err)),
1757        }
1758    }
1759
1760    /// Concatenate another [`UnsignedDecimal`] into the end of this [`UnsignedDecimal`].
1761    ///
1762    /// All nonzero digits in `other` must have lower magnitude than nonzero digits in `self`.
1763    /// If the two decimals represent overlapping ranges of magnitudes, an `Err` is returned,
1764    /// passing ownership of `other` back to the caller.
1765    ///
1766    /// The magnitude range of `self` will be increased if `other` covers a larger range.
1767    ///
1768    /// # Examples
1769    ///
1770    /// ```
1771    /// use fixed_decimal::UnsignedDecimal;
1772    ///
1773    /// let mut integer = UnsignedDecimal::from(123u32);
1774    /// let fraction = UnsignedDecimal::from(456u32).multiplied_pow10(-3);
1775    ///
1776    /// integer.concatenate_end(fraction);
1777    ///
1778    /// assert_eq!("123.456", integer.to_string());
1779    /// ```
1780    pub fn concatenate_end(&mut self, other: UnsignedDecimal) -> Result<(), UnsignedDecimal> {
1781        let self_right = self.nonzero_magnitude_end();
1782        let other_left = other.nonzero_magnitude_start();
1783        if self.is_zero() {
1784            // Operation will succeed. We can move the digits into self.
1785            self.digits = other.digits;
1786            self.magnitude = other.magnitude;
1787        } else if other.is_zero() {
1788            // No changes to the digits are necessary.
1789        } else if self_right <= other_left {
1790            // Illegal: `other` is not to the right of `self`
1791            return Err(other);
1792        } else {
1793            // Append the digits from other to the end of self
1794            let inner_zeroes = crate::ops::i16_abs_sub(self_right, other_left) as usize - 1;
1795            self.append_digits(inner_zeroes, &other.digits);
1796        }
1797        self.upper_magnitude = cmp::max(self.upper_magnitude, other.upper_magnitude);
1798        self.lower_magnitude = cmp::min(self.lower_magnitude, other.lower_magnitude);
1799        #[cfg(debug_assertions)]
1800        self.check_invariants();
1801        Ok(())
1802    }
1803
1804    /// Appends a slice of digits to the end of `self.digits` with optional inner zeroes.
1805    ///
1806    /// This function does not check invariants.
1807    fn append_digits(&mut self, inner_zeroes: usize, new_digits: &[u8]) {
1808        let new_len = self.digits.len() + inner_zeroes;
1809        self.digits.resize_with(new_len, || 0);
1810        self.digits.extend_from_slice(new_digits);
1811    }
1812
1813    /// Assert that the invariants among struct fields are enforced. Returns true if all are okay.
1814    /// Call this in any method that mutates the struct fields.
1815    ///
1816    /// Example: `debug_assert!(self.check_invariants())`
1817    #[cfg(debug_assertions)]
1818    #[allow(clippy::indexing_slicing)]
1819    fn check_invariants(&self) {
1820        // magnitude invariants:
1821        debug_assert!(
1822            self.upper_magnitude >= self.magnitude,
1823            "Upper magnitude too small {self:?}"
1824        );
1825        debug_assert!(
1826            self.lower_magnitude <= self.magnitude,
1827            "Lower magnitude too large {self:?}"
1828        );
1829        debug_assert!(
1830            self.upper_magnitude >= 0,
1831            "Upper magnitude below zero {self:?}"
1832        );
1833        debug_assert!(
1834            self.lower_magnitude <= 0,
1835            "Lower magnitude above zero {self:?}",
1836        );
1837
1838        // digits invariants:
1839        debug_assert!(
1840            self.digits.len() <= (self.magnitude as i32 - self.lower_magnitude as i32 + 1) as usize,
1841            "{self:?}"
1842        );
1843        if !self.digits.is_empty() {
1844            debug_assert_ne!(self.digits[0], 0, "Starts with a zero {self:?}");
1845            debug_assert_ne!(
1846                self.digits[self.digits.len() - 1],
1847                0,
1848                "Ends with a zero {self:?}",
1849            );
1850        } else {
1851            debug_assert_eq!(self.magnitude, 0);
1852        }
1853    }
1854}
1855
1856/// Render the `FixedDecimal` as a string of ASCII digits with a possible decimal point.
1857///
1858/// # Examples
1859///
1860/// ```
1861/// # use fixed_decimal::UnsignedDecimal;
1862/// # use writeable::assert_writeable_eq;
1863/// #
1864/// assert_writeable_eq!(UnsignedDecimal::from(42u32), "42");
1865/// ```
1866impl writeable::Writeable for UnsignedDecimal {
1867    fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
1868        for m in self.magnitude_range().rev() {
1869            if m == -1 {
1870                sink.write_char('.')?;
1871            }
1872            let d = self.digit_at(m);
1873            sink.write_char((b'0' + d) as char)?;
1874        }
1875        Ok(())
1876    }
1877
1878    fn writeable_length_hint(&self) -> writeable::LengthHint {
1879        writeable::LengthHint::exact(1)
1880            + ((self.upper_magnitude as i32 - self.lower_magnitude as i32) as usize)
1881            + (self.lower_magnitude < 0) as usize
1882    }
1883}
1884
1885writeable::impl_display_with_writeable!(UnsignedDecimal);
1886
1887impl UnsignedDecimal {
1888    #[inline]
1889    /// Parses a [`UnsignedDecimal`].
1890    pub fn try_from_str(s: &str) -> Result<Self, ParseError> {
1891        Self::try_from_utf8(s.as_bytes())
1892    }
1893
1894    /// This function is used to parse a [`UnsignedDecimal`] from a string without a sign.
1895    ///
1896    /// # Examples
1897    ///
1898    /// ```
1899    /// use fixed_decimal::ParseError;
1900    /// use fixed_decimal::UnsignedDecimal;
1901    ///
1902    /// let decimal = UnsignedDecimal::try_from_utf8(b"1234567890");
1903    /// assert_eq!(decimal, Ok(UnsignedDecimal::from(1234567890u32)));
1904    ///
1905    /// // In case of adding `+`, the function will return an error.
1906    /// let decimal = UnsignedDecimal::try_from_utf8(b"+1234567890");
1907    /// assert_eq!(decimal, Err(ParseError::Syntax));
1908    ///
1909    /// // In case of adding `-`, the function will return error
1910    /// let decimal = UnsignedDecimal::try_from_utf8(b"-1234567890");
1911    /// assert_eq!(decimal, Err(ParseError::Syntax));
1912    /// ```
1913    pub fn try_from_utf8(input_str: &[u8]) -> Result<Self, ParseError> {
1914        if input_str.is_empty() {
1915            return Err(ParseError::Syntax);
1916        }
1917
1918        // NOTE: this function assumes that the input string has no sign, this means if the string starts with `-` or `+`, it will be treated as a syntax error.
1919        Self::try_from_no_sign_utf8(input_str)
1920    }
1921
1922    pub(crate) fn try_from_no_sign_utf8(no_sign_str: &[u8]) -> Result<Self, ParseError> {
1923        // Compute length of each string once and store it, so if you use that multiple times,
1924        // you don't compute it multiple times
1925        // has_dot: shows if your input has dot in it
1926        // has_exponent: shows if your input has an exponent in it
1927        // dot_index: gives the index of dot (after removing the sign) -- equal to length of
1928        // the no_sign_str if there is no dot
1929        // exponent_index: gives the index of exponent (after removing the sign) -- equal to length of
1930        // the no_sign_str if there is no dot
1931        let mut has_dot = false;
1932        let mut has_exponent = false;
1933        let mut dot_index = no_sign_str.len();
1934        let mut exponent_index = no_sign_str.len();
1935        // The following loop computes has_dot, dot_index, and also checks to see if all
1936        // characters are digits and if you have at most one dot
1937        // Note: Input of format 111_123 is detected as syntax error here
1938        // Note: Input starting or ending with a dot is detected as syntax error here (Ex: .123, 123.)
1939        for (i, c) in no_sign_str.iter().enumerate() {
1940            if *c == b'.' {
1941                if has_dot || has_exponent {
1942                    // multiple dots or dots after the exponent
1943                    return Err(ParseError::Syntax);
1944                }
1945                dot_index = i;
1946                has_dot = true;
1947                // We do support omitting the leading zero,
1948                // but not trailing decimal points
1949                if i == no_sign_str.len() - 1 {
1950                    return Err(ParseError::Syntax);
1951                }
1952            } else if *c == b'e' || *c == b'E' {
1953                if has_exponent {
1954                    // multiple exponents
1955                    return Err(ParseError::Syntax);
1956                }
1957                exponent_index = i;
1958                has_exponent = true;
1959                if i == 0 || i == no_sign_str.len() - 1 {
1960                    return Err(ParseError::Syntax);
1961                }
1962            } else if *c == b'-' {
1963                // Allow a single minus sign after the exponent
1964                if has_exponent && exponent_index == i - 1 {
1965                    continue;
1966                } else {
1967                    return Err(ParseError::Syntax);
1968                }
1969            } else if *c < b'0' || *c > b'9' {
1970                return Err(ParseError::Syntax);
1971            }
1972        }
1973
1974        // The string without the exponent (or sign)
1975        // We do the bulk of the calculation on this string,
1976        // and extract the exponent at the end
1977        #[allow(clippy::indexing_slicing)] // exponent_index comes from enumerate
1978        let no_exponent_str = &no_sign_str[..exponent_index];
1979
1980        // If there was no dot, truncate the dot index
1981        if dot_index > exponent_index {
1982            dot_index = exponent_index;
1983        }
1984
1985        // defining the output dec here and set its sign
1986        let mut dec = Self::default();
1987
1988        // no_dot_str_len: shows length of the string after removing the dot
1989        let mut no_dot_str_len = no_exponent_str.len();
1990        if has_dot {
1991            no_dot_str_len -= 1;
1992        }
1993
1994        // Computing DecimalFixed.upper_magnitude
1995        // We support strings like `0.x` and `.x`. The upper magnitude
1996        // is always one less than the position of the dot, except in the case where
1997        // the 0 is omitted; when dot_index = 0. We use saturating_sub to set
1998        // magnitude to 0 in that case.
1999        let temp_upper_magnitude = dot_index.saturating_sub(1);
2000        if temp_upper_magnitude > i16::MAX as usize {
2001            return Err(ParseError::Limit);
2002        }
2003        dec.upper_magnitude = temp_upper_magnitude as i16;
2004
2005        // Computing DecimalFixed.lower_magnitude
2006        let temp_lower_magnitude = no_dot_str_len - dot_index;
2007        if temp_lower_magnitude > (i16::MIN as u16) as usize {
2008            return Err(ParseError::Limit);
2009        }
2010        dec.lower_magnitude = (temp_lower_magnitude as i16).wrapping_neg();
2011
2012        // leftmost_digit: index of the first non-zero digit
2013        // rightmost_digit: index of the first element after the last non-zero digit
2014        // Example:
2015        //     input string    leftmost_digit     rightmost_digit
2016        //     00123000              2                  5
2017        //     0.0123000             3                  6
2018        //     001.23000             2                  6
2019        //     001230.00             2                  5
2020        // Compute leftmost_digit
2021        let leftmost_digit = no_exponent_str
2022            .iter()
2023            .position(|c| *c != b'.' && *c != b'0');
2024
2025        // If the input only has zeros (like 000, 00.0, -00.000) we handle the situation here
2026        // by returning the dec and don't running the rest of the code
2027        let leftmost_digit = if let Some(leftmost_digit) = leftmost_digit {
2028            leftmost_digit
2029        } else {
2030            return Ok(dec);
2031        };
2032
2033        // Else if the input is not all zeros, we compute its magnitude:
2034        // Note that we can cast with "as" here because lower and upper magnitude have been checked already
2035        let mut temp_magnitude = ((dot_index as i32) - (leftmost_digit as i32) - 1i32) as i16;
2036        if dot_index < leftmost_digit {
2037            temp_magnitude += 1;
2038        }
2039        dec.magnitude = temp_magnitude;
2040
2041        // Compute the index where the rightmost_digit ends
2042        let rightmost_digit_end = no_exponent_str
2043            .iter()
2044            .rposition(|c| *c != b'.' && *c != b'0')
2045            .map(|p| p + 1)
2046            .unwrap_or(no_exponent_str.len());
2047
2048        // digits_str_len: shows the length of digits (Ex. 0012.8900 --> 4)
2049        let mut digits_str_len = rightmost_digit_end - leftmost_digit;
2050        if leftmost_digit < dot_index && dot_index < rightmost_digit_end {
2051            digits_str_len -= 1;
2052        }
2053
2054        // Constructing DecimalFixed.digits
2055        #[allow(clippy::indexing_slicing)]
2056        // leftmost_digit  and rightmost_digit_end come from Iterator::position and Iterator::rposition.
2057        let v: SmallVec<[u8; 8]> = no_exponent_str[leftmost_digit..rightmost_digit_end]
2058            .iter()
2059            .filter(|c| **c != b'.')
2060            .map(|c| c - b'0')
2061            .collect();
2062
2063        let v_len = v.len();
2064        debug_assert_eq!(v_len, digits_str_len);
2065        dec.digits = v;
2066
2067        // Extract the exponent part
2068        if has_exponent {
2069            let mut pow = 0;
2070            let mut pos_neg = 1;
2071            #[allow(clippy::indexing_slicing)]
2072            // exponent_index is exist, then exponent_index + 1 will equal at most no_sign_str.len().
2073            for digit in &no_sign_str[exponent_index + 1..] {
2074                if *digit == b'-' {
2075                    pos_neg = -1;
2076                    continue;
2077                }
2078                pow *= 10;
2079                pow += (digit - b'0') as i16;
2080            }
2081
2082            dec.multiply_pow10(pos_neg * pow);
2083
2084            // Clean up magnitude after multiplication
2085            if dec.magnitude > 0 {
2086                dec.upper_magnitude = dec.magnitude;
2087            }
2088            let neg_mag = dec.magnitude - dec.digits.len() as i16 + 1;
2089            if neg_mag < 0 {
2090                dec.lower_magnitude = neg_mag;
2091            }
2092        }
2093
2094        Ok(dec)
2095    }
2096}
2097
2098impl FromStr for UnsignedDecimal {
2099    type Err = ParseError;
2100    fn from_str(s: &str) -> Result<Self, Self::Err> {
2101        Self::try_from_str(s)
2102    }
2103}
2104
2105#[cfg(feature = "ryu")]
2106impl UnsignedDecimal {
2107    /// Constructs a [`UnsignedDecimal`] from an f64.
2108    ///
2109    /// Since f64 values do not carry a notion of their precision, the second argument to this
2110    /// function specifies the type of precision associated with the f64. For more information,
2111    /// see [`FloatPrecision`].
2112    ///
2113    /// This function uses `ryu`, which is an efficient double-to-string algorithm, but other
2114    /// implementations may yield higher performance; for more details, see
2115    /// [icu4x#166](https://github.com/unicode-org/icu4x/issues/166).
2116    ///
2117    /// This function can be made available with the `"ryu"` Cargo feature.
2118    ///
2119    /// NOTE:
2120    ///   Negative numbers are not supported.
2121    ///
2122    /// ```rust
2123    /// use fixed_decimal::{FloatPrecision, UnsignedDecimal};
2124    /// use writeable::assert_writeable_eq;
2125    ///
2126    /// let decimal =
2127    ///     UnsignedDecimal::try_from_f64(-5.1, FloatPrecision::Magnitude(-2))
2128    ///         .expect_err("Negative numbers are not supported");
2129    ///
2130    /// let decimal =
2131    ///     UnsignedDecimal::try_from_f64(0.012345678, FloatPrecision::RoundTrip)
2132    ///         .expect("Finite quantity");
2133    /// assert_writeable_eq!(decimal, "0.012345678");
2134    ///
2135    /// let decimal =
2136    ///     UnsignedDecimal::try_from_f64(12345678000., FloatPrecision::Integer)
2137    ///         .expect("Finite, integer-valued quantity");
2138    /// assert_writeable_eq!(decimal, "12345678000");
2139    /// ```
2140    pub fn try_from_f64(float: f64, precision: FloatPrecision) -> Result<Self, LimitError> {
2141        let mut decimal = Self::new_from_f64_raw(float)?;
2142        let n_digits = decimal.digits.len();
2143        // magnitude of the lowest digit in self.digits
2144        let lowest_magnitude = decimal.magnitude - n_digits as i16 + 1;
2145        // ryū will usually tack on a `.0` to integers which gets included when parsing.
2146        // Explicitly remove it before doing anything else
2147        if lowest_magnitude >= 0 && decimal.lower_magnitude < 0 {
2148            decimal.lower_magnitude = 0;
2149        }
2150        match precision {
2151            FloatPrecision::RoundTrip => (),
2152            FloatPrecision::Integer => {
2153                if lowest_magnitude < 0 {
2154                    return Err(LimitError);
2155                }
2156            }
2157            FloatPrecision::Magnitude(mag) => {
2158                decimal.round(mag);
2159            }
2160            FloatPrecision::SignificantDigits(sig) => {
2161                if sig == 0 {
2162                    return Err(LimitError);
2163                }
2164
2165                let position = decimal.magnitude - (sig as i16) + 1;
2166                let old_magnitude = decimal.magnitude;
2167                decimal.round(position);
2168
2169                // This means the significant digits has been increased by 1.
2170                if decimal.magnitude > old_magnitude {
2171                    decimal.lower_magnitude = cmp::min(0, position + 1);
2172                }
2173            }
2174        }
2175        #[cfg(debug_assertions)]
2176        decimal.check_invariants();
2177        Ok(decimal)
2178    }
2179
2180    /// Internal function for parsing directly from floats using ryū
2181    fn new_from_f64_raw(float: f64) -> Result<Self, LimitError> {
2182        if !float.is_finite() || float.is_sign_negative() {
2183            return Err(LimitError);
2184        }
2185        // note: this does not heap allocate
2186        let mut buf = ryu::Buffer::new();
2187        let formatted = buf.format_finite(float);
2188        Self::from_str(formatted).map_err(|e| match e {
2189            ParseError::Limit => LimitError,
2190            ParseError::Syntax => unreachable!("ryu produces correct syntax"),
2191        })
2192    }
2193}
2194
2195#[cfg(feature = "ryu")]
2196#[test]
2197fn test_float() {
2198    #[derive(Debug)]
2199    struct TestCase {
2200        pub input: f64,
2201        pub precision: FloatPrecision,
2202        pub expected: &'static str,
2203    }
2204    let cases = [
2205        TestCase {
2206            input: 1.234567,
2207            precision: FloatPrecision::RoundTrip,
2208            expected: "1.234567",
2209        },
2210        TestCase {
2211            input: 888999.,
2212            precision: FloatPrecision::RoundTrip,
2213            expected: "888999",
2214        },
2215        // HalfExpand tests
2216        TestCase {
2217            input: 1.234567,
2218            precision: FloatPrecision::Magnitude(-2),
2219            expected: "1.23",
2220        },
2221        TestCase {
2222            input: 1.235567,
2223            precision: FloatPrecision::Magnitude(-2),
2224            expected: "1.24",
2225        },
2226        TestCase {
2227            input: 1.2002,
2228            precision: FloatPrecision::Magnitude(-3),
2229            expected: "1.200",
2230        },
2231        TestCase {
2232            input: 888999.,
2233            precision: FloatPrecision::Magnitude(2),
2234            expected: "889000",
2235        },
2236        TestCase {
2237            input: 888999.,
2238            precision: FloatPrecision::Magnitude(4),
2239            expected: "890000",
2240        },
2241        TestCase {
2242            input: 0.9,
2243            precision: FloatPrecision::Magnitude(0),
2244            expected: "1",
2245        },
2246        TestCase {
2247            input: 0.9,
2248            precision: FloatPrecision::Magnitude(2),
2249            expected: "00",
2250        },
2251        TestCase {
2252            input: 0.009,
2253            precision: FloatPrecision::Magnitude(-2),
2254            expected: "0.01",
2255        },
2256        TestCase {
2257            input: 0.009,
2258            precision: FloatPrecision::Magnitude(-1),
2259            expected: "0.0",
2260        },
2261        TestCase {
2262            input: 0.009,
2263            precision: FloatPrecision::Magnitude(0),
2264            expected: "0",
2265        },
2266        TestCase {
2267            input: 0.0000009,
2268            precision: FloatPrecision::Magnitude(0),
2269            expected: "0",
2270        },
2271        TestCase {
2272            input: 0.0000009,
2273            precision: FloatPrecision::Magnitude(-7),
2274            expected: "0.0000009",
2275        },
2276        TestCase {
2277            input: 0.0000009,
2278            precision: FloatPrecision::Magnitude(-6),
2279            expected: "0.000001",
2280        },
2281        TestCase {
2282            input: 1.234567,
2283            precision: FloatPrecision::SignificantDigits(1),
2284            expected: "1",
2285        },
2286        TestCase {
2287            input: 1.234567,
2288            precision: FloatPrecision::SignificantDigits(2),
2289            expected: "1.2",
2290        },
2291        TestCase {
2292            input: 1.234567,
2293            precision: FloatPrecision::SignificantDigits(4),
2294            expected: "1.235",
2295        },
2296        TestCase {
2297            input: 1.234567,
2298            precision: FloatPrecision::SignificantDigits(10),
2299            expected: "1.234567000",
2300        },
2301        TestCase {
2302            input: 888999.,
2303            precision: FloatPrecision::SignificantDigits(1),
2304            expected: "900000",
2305        },
2306        TestCase {
2307            input: 888999.,
2308            precision: FloatPrecision::SignificantDigits(2),
2309            expected: "890000",
2310        },
2311        TestCase {
2312            input: 888999.,
2313            precision: FloatPrecision::SignificantDigits(4),
2314            expected: "889000",
2315        },
2316        TestCase {
2317            input: 988999.,
2318            precision: FloatPrecision::SignificantDigits(1),
2319            expected: "1000000",
2320        },
2321        TestCase {
2322            input: 99888.,
2323            precision: FloatPrecision::SignificantDigits(1),
2324            expected: "100000",
2325        },
2326        TestCase {
2327            input: 99888.,
2328            precision: FloatPrecision::SignificantDigits(2),
2329            expected: "100000",
2330        },
2331        TestCase {
2332            input: 99888.,
2333            precision: FloatPrecision::SignificantDigits(3),
2334            expected: "99900",
2335        },
2336        TestCase {
2337            input: 0.0099,
2338            precision: FloatPrecision::SignificantDigits(1),
2339            expected: "0.01",
2340        },
2341        TestCase {
2342            input: 9.9888,
2343            precision: FloatPrecision::SignificantDigits(1),
2344            expected: "10",
2345        },
2346        TestCase {
2347            input: 9.9888,
2348            precision: FloatPrecision::SignificantDigits(2),
2349            expected: "10",
2350        },
2351        TestCase {
2352            input: 99888.0,
2353            precision: FloatPrecision::SignificantDigits(1),
2354            expected: "100000",
2355        },
2356        TestCase {
2357            input: 99888.0,
2358            precision: FloatPrecision::SignificantDigits(2),
2359            expected: "100000",
2360        },
2361        TestCase {
2362            input: 9.9888,
2363            precision: FloatPrecision::SignificantDigits(3),
2364            expected: "9.99",
2365        },
2366    ];
2367
2368    for case in &cases {
2369        let dec = UnsignedDecimal::try_from_f64(case.input, case.precision).unwrap();
2370        writeable::assert_writeable_eq!(dec, case.expected, "{:?}", case);
2371    }
2372}
2373
2374#[test]
2375fn test_basic() {
2376    #[derive(Debug)]
2377    struct TestCase {
2378        pub input: usize,
2379        pub delta: i16,
2380        pub expected: &'static str,
2381    }
2382    let cases = [
2383        TestCase {
2384            input: 51423,
2385            delta: 0,
2386            expected: "51423",
2387        },
2388        TestCase {
2389            input: 51423,
2390            delta: -2,
2391            expected: "514.23",
2392        },
2393        TestCase {
2394            input: 51423,
2395            delta: -5,
2396            expected: "0.51423",
2397        },
2398        TestCase {
2399            input: 51423,
2400            delta: -8,
2401            expected: "0.00051423",
2402        },
2403        TestCase {
2404            input: 51423,
2405            delta: 3,
2406            expected: "51423000",
2407        },
2408        TestCase {
2409            input: 0,
2410            delta: 0,
2411            expected: "0",
2412        },
2413        TestCase {
2414            input: 0,
2415            delta: -2,
2416            expected: "0.00",
2417        },
2418        TestCase {
2419            input: 0,
2420            delta: 3,
2421            expected: "0000",
2422        },
2423        TestCase {
2424            input: 500,
2425            delta: 0,
2426            expected: "500",
2427        },
2428        TestCase {
2429            input: 500,
2430            delta: -1,
2431            expected: "50.0",
2432        },
2433        TestCase {
2434            input: 500,
2435            delta: -2,
2436            expected: "5.00",
2437        },
2438        TestCase {
2439            input: 500,
2440            delta: -3,
2441            expected: "0.500",
2442        },
2443        TestCase {
2444            input: 500,
2445            delta: -4,
2446            expected: "0.0500",
2447        },
2448        TestCase {
2449            input: 500,
2450            delta: 3,
2451            expected: "500000",
2452        },
2453    ];
2454    for cas in &cases {
2455        let mut dec: UnsignedDecimal = cas.input.into();
2456        // println!("{}", cas.input + 0.01);
2457        dec.multiply_pow10(cas.delta);
2458        writeable::assert_writeable_eq!(dec, cas.expected, "{:?}", cas);
2459    }
2460}
2461
2462#[test]
2463fn test_from_str() {
2464    #[derive(Debug)]
2465    struct TestCase {
2466        pub input_str: &'static str,
2467        /// The output str, `None` for roundtrip
2468        pub output_str: Option<&'static str>,
2469        /// [upper magnitude, upper nonzero magnitude, lower nonzero magnitude, lower magnitude]
2470        pub magnitudes: [i16; 4],
2471    }
2472    let cases = [
2473        TestCase {
2474            input_str: "00123400",
2475            output_str: None,
2476            magnitudes: [7, 5, 2, 0],
2477        },
2478        TestCase {
2479            input_str: "0.0123400",
2480            output_str: None,
2481            magnitudes: [0, -2, -5, -7],
2482        },
2483        TestCase {
2484            input_str: "0012.3400",
2485            output_str: None,
2486            magnitudes: [3, 1, -2, -4],
2487        },
2488        TestCase {
2489            input_str: "1234",
2490            output_str: None,
2491            magnitudes: [3, 3, 0, 0],
2492        },
2493        TestCase {
2494            input_str: "1000000",
2495            output_str: None,
2496            magnitudes: [6, 6, 6, 0],
2497        },
2498        TestCase {
2499            input_str: "10000001",
2500            output_str: None,
2501            magnitudes: [7, 7, 0, 0],
2502        },
2503        TestCase {
2504            input_str: "123",
2505            output_str: None,
2506            magnitudes: [2, 2, 0, 0],
2507        },
2508        TestCase {
2509            input_str: "922337203685477580898230948203840239384.9823094820384023938423424",
2510            output_str: None,
2511            magnitudes: [38, 38, -25, -25],
2512        },
2513        TestCase {
2514            input_str: "009223372000.003685477580898230948203840239384000",
2515            output_str: None,
2516            magnitudes: [11, 9, -33, -36],
2517        },
2518        TestCase {
2519            input_str: "0",
2520            output_str: None,
2521            magnitudes: [0, 0, 0, 0],
2522        },
2523        TestCase {
2524            input_str: "000",
2525            output_str: None,
2526            magnitudes: [2, 0, 0, 0],
2527        },
2528        // no leading 0 parsing
2529        TestCase {
2530            input_str: ".0123400",
2531            output_str: Some("0.0123400"),
2532            magnitudes: [0, -2, -5, -7],
2533        },
2534        TestCase {
2535            input_str: ".000000001",
2536            output_str: Some("0.000000001"),
2537            magnitudes: [0, -9, -9, -9],
2538        },
2539    ];
2540    for cas in &cases {
2541        println!("cas: {:?}", cas);
2542        let fd = UnsignedDecimal::from_str(cas.input_str).unwrap();
2543        assert_eq!(
2544            fd.magnitude_range(),
2545            cas.magnitudes[3]..=cas.magnitudes[0],
2546            "{cas:?}"
2547        );
2548        assert_eq!(fd.nonzero_magnitude_start(), cas.magnitudes[1], "{cas:?}");
2549        assert_eq!(fd.nonzero_magnitude_end(), cas.magnitudes[2], "{cas:?}");
2550        let input_str_roundtrip = fd.to_string();
2551        let output_str = cas.output_str.unwrap_or(cas.input_str);
2552
2553        // Check if the output string starts with a plus sign and remove it,
2554        // because we do not show sign for unsigned fixed decimal
2555        let output_str = match output_str.strip_prefix('+') {
2556            Some(stripped) => stripped,
2557            None => output_str,
2558        };
2559        assert_eq!(output_str, input_str_roundtrip, "{cas:?}");
2560    }
2561}
2562
2563#[test]
2564fn test_from_str_scientific() {
2565    #[derive(Debug)]
2566    struct TestCase {
2567        pub input_str: &'static str,
2568        pub output: &'static str,
2569    }
2570    let cases = [
2571        TestCase {
2572            input_str: "5.4e-2",
2573            output: "0.054",
2574        },
2575        TestCase {
2576            input_str: "54.1e-2",
2577            output: "0.541",
2578        },
2579        TestCase {
2580            input_str: "0.009E10",
2581            output: "90000000",
2582        },
2583    ];
2584    for cas in &cases {
2585        let input_str_roundtrip = UnsignedDecimal::from_str(cas.input_str)
2586            .unwrap()
2587            .to_string();
2588        assert_eq!(cas.output, input_str_roundtrip);
2589    }
2590}
2591
2592#[test]
2593fn test_usize_limits() {
2594    for num in &[usize::MAX, usize::MIN] {
2595        let dec: UnsignedDecimal = (*num).into();
2596        let dec_str = dec.to_string();
2597        assert_eq!(num.to_string(), dec_str);
2598        assert_eq!(dec, UnsignedDecimal::from_str(&dec_str).unwrap());
2599        writeable::assert_writeable_eq!(dec, dec_str);
2600    }
2601}
2602
2603#[test]
2604fn test_u128_limits() {
2605    for num in &[u128::MAX, u128::MIN] {
2606        let dec: UnsignedDecimal = (*num).into();
2607        let dec_str = dec.to_string();
2608        assert_eq!(num.to_string(), dec_str);
2609        assert_eq!(dec, UnsignedDecimal::from_str(&dec_str).unwrap());
2610        writeable::assert_writeable_eq!(dec, dec_str);
2611    }
2612}
2613
2614#[test]
2615fn test_upper_magnitude_bounds() {
2616    let mut dec: UnsignedDecimal = 98765u32.into();
2617    assert_eq!(dec.upper_magnitude, 4);
2618    dec.multiply_pow10(i16::MAX - 4);
2619    assert_eq!(dec.upper_magnitude, i16::MAX);
2620    assert_eq!(dec.nonzero_magnitude_start(), i16::MAX);
2621    let dec_backup = dec.clone();
2622    dec.multiply_pow10(1);
2623    assert!(dec.is_zero());
2624    assert_ne!(dec, dec_backup, "Value should be unchanged on failure");
2625
2626    // Checking from_str for dec (which is valid)
2627    let dec_roundtrip = UnsignedDecimal::from_str(&dec.to_string()).unwrap();
2628    assert_eq!(dec, dec_roundtrip);
2629}
2630
2631#[test]
2632fn test_lower_magnitude_bounds() {
2633    let mut dec: UnsignedDecimal = 98765u32.into();
2634    assert_eq!(dec.lower_magnitude, 0);
2635    dec.multiply_pow10(i16::MIN);
2636    assert_eq!(dec.lower_magnitude, i16::MIN);
2637    assert_eq!(dec.nonzero_magnitude_end(), i16::MIN);
2638    let dec_backup = dec.clone();
2639    dec.multiply_pow10(-1);
2640    assert!(dec.is_zero());
2641    assert_ne!(dec, dec_backup);
2642
2643    // Checking from_str for dec (which is valid)
2644    let dec_roundtrip = UnsignedDecimal::from_str(&dec.to_string()).unwrap();
2645    assert_eq!(dec, dec_roundtrip);
2646}
2647
2648#[test]
2649fn test_zero_str_bounds() {
2650    #[derive(Debug)]
2651    struct TestCase {
2652        pub zeros_before_dot: usize,
2653        pub zeros_after_dot: usize,
2654        pub expected_err: Option<ParseError>,
2655    }
2656    let cases = [
2657        TestCase {
2658            zeros_before_dot: i16::MAX as usize + 1,
2659            zeros_after_dot: 0,
2660            expected_err: None,
2661        },
2662        TestCase {
2663            zeros_before_dot: i16::MAX as usize,
2664            zeros_after_dot: 0,
2665            expected_err: None,
2666        },
2667        TestCase {
2668            zeros_before_dot: i16::MAX as usize + 2,
2669            zeros_after_dot: 0,
2670            expected_err: Some(ParseError::Limit),
2671        },
2672        TestCase {
2673            zeros_before_dot: 0,
2674            zeros_after_dot: i16::MAX as usize + 2,
2675            expected_err: Some(ParseError::Limit),
2676        },
2677        TestCase {
2678            zeros_before_dot: i16::MAX as usize + 1,
2679            zeros_after_dot: i16::MAX as usize + 1,
2680            expected_err: None,
2681        },
2682        TestCase {
2683            zeros_before_dot: i16::MAX as usize + 2,
2684            zeros_after_dot: i16::MAX as usize + 1,
2685            expected_err: Some(ParseError::Limit),
2686        },
2687        TestCase {
2688            zeros_before_dot: i16::MAX as usize + 1,
2689            zeros_after_dot: i16::MAX as usize + 2,
2690            expected_err: Some(ParseError::Limit),
2691        },
2692        TestCase {
2693            zeros_before_dot: i16::MAX as usize,
2694            zeros_after_dot: i16::MAX as usize + 2,
2695            expected_err: Some(ParseError::Limit),
2696        },
2697        TestCase {
2698            zeros_before_dot: i16::MAX as usize,
2699            zeros_after_dot: i16::MAX as usize,
2700            expected_err: None,
2701        },
2702        TestCase {
2703            zeros_before_dot: i16::MAX as usize + 1,
2704            zeros_after_dot: i16::MAX as usize,
2705            expected_err: None,
2706        },
2707    ];
2708    for cas in &cases {
2709        let mut input_str = format!("{:0fill$}", 0, fill = cas.zeros_before_dot);
2710        if cas.zeros_after_dot > 0 {
2711            input_str.push('.');
2712            input_str.push_str(&format!("{:0fill$}", 0, fill = cas.zeros_after_dot));
2713        }
2714        match UnsignedDecimal::from_str(&input_str) {
2715            Ok(dec) => {
2716                assert_eq!(cas.expected_err, None, "{cas:?}");
2717                assert_eq!(input_str, dec.to_string(), "{cas:?}");
2718            }
2719            Err(err) => {
2720                assert_eq!(cas.expected_err, Some(err), "{cas:?}");
2721            }
2722        }
2723    }
2724}
2725
2726#[test]
2727fn test_syntax_error() {
2728    #[derive(Debug)]
2729    struct TestCase {
2730        pub input_str: &'static str,
2731        pub expected_err: Option<ParseError>,
2732    }
2733    let cases = [
2734        TestCase {
2735            input_str: "+1234567890",
2736            expected_err: Some(ParseError::Syntax),
2737        },
2738        TestCase {
2739            input_str: "-1234567890",
2740            expected_err: Some(ParseError::Syntax),
2741        },
2742        TestCase {
2743            input_str: "-12a34",
2744            expected_err: Some(ParseError::Syntax),
2745        },
2746        TestCase {
2747            input_str: "0.0123√400",
2748            expected_err: Some(ParseError::Syntax),
2749        },
2750        TestCase {
2751            input_str: "0.012.3400",
2752            expected_err: Some(ParseError::Syntax),
2753        },
2754        TestCase {
2755            input_str: "-0-0123400",
2756            expected_err: Some(ParseError::Syntax),
2757        },
2758        TestCase {
2759            input_str: "0-0123400",
2760            expected_err: Some(ParseError::Syntax),
2761        },
2762        TestCase {
2763            input_str: "-0.00123400",
2764            expected_err: Some(ParseError::Syntax),
2765        },
2766        TestCase {
2767            input_str: "00123400.",
2768            expected_err: Some(ParseError::Syntax),
2769        },
2770        TestCase {
2771            input_str: "00123400.0",
2772            expected_err: None,
2773        },
2774        TestCase {
2775            input_str: "123_456",
2776            expected_err: Some(ParseError::Syntax),
2777        },
2778        TestCase {
2779            input_str: "",
2780            expected_err: Some(ParseError::Syntax),
2781        },
2782        TestCase {
2783            input_str: "-",
2784            expected_err: Some(ParseError::Syntax),
2785        },
2786        TestCase {
2787            input_str: "+",
2788            expected_err: Some(ParseError::Syntax),
2789        },
2790        TestCase {
2791            input_str: "-1",
2792            expected_err: Some(ParseError::Syntax),
2793        },
2794    ];
2795    for cas in &cases {
2796        match UnsignedDecimal::from_str(cas.input_str) {
2797            Ok(dec) => {
2798                assert_eq!(cas.expected_err, None, "{cas:?}");
2799                assert_eq!(cas.input_str, dec.to_string(), "{cas:?}");
2800            }
2801            Err(err) => {
2802                assert_eq!(cas.expected_err, Some(err), "{cas:?}");
2803            }
2804        }
2805    }
2806}
2807
2808#[test]
2809fn test_pad() {
2810    let mut dec = UnsignedDecimal::from_str("0.42").unwrap();
2811    assert_eq!("0.42", dec.to_string());
2812
2813    dec.pad_start(1);
2814    assert_eq!("0.42", dec.to_string());
2815
2816    dec.pad_start(4);
2817    assert_eq!("0000.42", dec.to_string());
2818
2819    dec.pad_start(2);
2820    assert_eq!("00.42", dec.to_string());
2821}
2822
2823#[test]
2824fn test_set_max_position() {
2825    let mut dec = UnsignedDecimal::from(1000u32);
2826    assert_eq!("1000", dec.to_string());
2827
2828    dec.set_max_position(2);
2829    assert_eq!("00", dec.to_string());
2830
2831    dec.set_max_position(0);
2832    assert_eq!("0", dec.to_string());
2833
2834    dec.set_max_position(3);
2835    assert_eq!("000", dec.to_string());
2836
2837    let mut dec = UnsignedDecimal::from_str("0.456").unwrap();
2838    assert_eq!("0.456", dec.to_string());
2839
2840    dec.set_max_position(0);
2841    assert_eq!("0.456", dec.to_string());
2842
2843    dec.set_max_position(-1);
2844    assert_eq!("0.056", dec.to_string());
2845
2846    dec.set_max_position(-2);
2847    assert_eq!("0.006", dec.to_string());
2848
2849    dec.set_max_position(-3);
2850    assert_eq!("0.000", dec.to_string());
2851
2852    dec.set_max_position(-4);
2853    assert_eq!("0.0000", dec.to_string());
2854
2855    let mut dec = UnsignedDecimal::from_str("100.01").unwrap();
2856    dec.set_max_position(1);
2857    assert_eq!("0.01", dec.to_string());
2858}
2859
2860#[test]
2861fn test_pad_start_bounds() {
2862    let mut dec = UnsignedDecimal::from_str("299792.458").unwrap();
2863    let max_integer_digits = i16::MAX as usize + 1;
2864
2865    dec.pad_start(i16::MAX - 1);
2866    assert_eq!(
2867        max_integer_digits - 2,
2868        dec.to_string().split_once('.').unwrap().0.len()
2869    );
2870
2871    dec.pad_start(i16::MAX);
2872    assert_eq!(
2873        max_integer_digits - 1,
2874        dec.to_string().split_once('.').unwrap().0.len()
2875    );
2876}
2877
2878#[test]
2879fn test_pad_end_bounds() {
2880    let mut dec = UnsignedDecimal::from_str("299792.458").unwrap();
2881    let max_fractional_digits = -(i16::MIN as isize) as usize;
2882
2883    dec.pad_end(i16::MIN + 1);
2884    assert_eq!(
2885        max_fractional_digits - 1,
2886        dec.to_string().split_once('.').unwrap().1.len()
2887    );
2888
2889    dec.pad_end(i16::MIN);
2890    assert_eq!(
2891        max_fractional_digits,
2892        dec.to_string().split_once('.').unwrap().1.len()
2893    );
2894}
2895
2896#[test]
2897fn test_rounding() {
2898    pub(crate) use std::str::FromStr;
2899
2900    // Test Truncate Right
2901    let mut dec = UnsignedDecimal::from(4235970u32).multiplied_pow10(-3);
2902    assert_eq!("4235.970", dec.to_string());
2903
2904    dec.trunc(-5);
2905    assert_eq!("4235.97000", dec.to_string());
2906
2907    dec.trunc(-1);
2908    assert_eq!("4235.9", dec.to_string());
2909
2910    dec.trunc(0);
2911    assert_eq!("4235", dec.to_string());
2912
2913    dec.trunc(1);
2914    assert_eq!("4230", dec.to_string());
2915
2916    dec.trunc(5);
2917    assert_eq!("00000", dec.to_string());
2918
2919    dec.trunc(2);
2920    assert_eq!("00000", dec.to_string());
2921
2922    let mut dec = UnsignedDecimal::from_str("1234.56").unwrap();
2923    dec.trunc(-1);
2924    assert_eq!("1234.5", dec.to_string());
2925
2926    let mut dec = UnsignedDecimal::from_str("0.009").unwrap();
2927    dec.trunc(-1);
2928    assert_eq!("0.0", dec.to_string());
2929
2930    // Test trunced
2931    let dec = UnsignedDecimal::from(4235970u32).multiplied_pow10(-3);
2932    assert_eq!("4235.970", dec.to_string());
2933
2934    assert_eq!("4235.97000", dec.clone().trunced(-5).to_string());
2935
2936    assert_eq!("4230", dec.clone().trunced(1).to_string());
2937
2938    assert_eq!("4200", dec.clone().trunced(2).to_string());
2939
2940    assert_eq!("00000", dec.trunced(5).to_string());
2941
2942    //Test expand
2943    let mut dec = UnsignedDecimal::from_str("3.234").unwrap();
2944    dec.expand(0);
2945    assert_eq!("4", dec.to_string());
2946
2947    let mut dec = UnsignedDecimal::from_str("2.222").unwrap();
2948    dec.expand(-1);
2949    assert_eq!("2.3", dec.to_string());
2950
2951    let mut dec = UnsignedDecimal::from_str("22.222").unwrap();
2952    dec.expand(-2);
2953    assert_eq!("22.23", dec.to_string());
2954
2955    let mut dec = UnsignedDecimal::from_str("99.999").unwrap();
2956    dec.expand(-2);
2957    assert_eq!("100.00", dec.to_string());
2958
2959    let mut dec = UnsignedDecimal::from_str("99.999").unwrap();
2960    dec.expand(-5);
2961    assert_eq!("99.99900", dec.to_string());
2962
2963    let mut dec = UnsignedDecimal::from_str("99.999").unwrap();
2964    dec.expand(4);
2965    assert_eq!("10000", dec.to_string());
2966
2967    let mut dec = UnsignedDecimal::from_str("0.009").unwrap();
2968    dec.expand(-1);
2969    assert_eq!("0.1", dec.to_string());
2970
2971    let mut dec = UnsignedDecimal::from_str("3.954").unwrap();
2972    dec.expand(0);
2973    assert_eq!("4", dec.to_string());
2974
2975    // Test half_expand
2976    let mut dec = UnsignedDecimal::from_str("3.234").unwrap();
2977    dec.round_with_mode(0, UnsignedRoundingMode::HalfExpand);
2978    assert_eq!("3", dec.to_string());
2979
2980    let mut dec = UnsignedDecimal::from_str("3.534").unwrap();
2981    dec.round_with_mode(0, UnsignedRoundingMode::HalfExpand);
2982    assert_eq!("4", dec.to_string());
2983
2984    let mut dec = UnsignedDecimal::from_str("3.934").unwrap();
2985    dec.round_with_mode(0, UnsignedRoundingMode::HalfExpand);
2986    assert_eq!("4", dec.to_string());
2987
2988    let mut dec = UnsignedDecimal::from_str("2.222").unwrap();
2989    dec.round_with_mode(-1, UnsignedRoundingMode::HalfExpand);
2990    assert_eq!("2.2", dec.to_string());
2991
2992    let mut dec = UnsignedDecimal::from_str("2.44").unwrap();
2993    dec.round_with_mode(-1, UnsignedRoundingMode::HalfExpand);
2994    assert_eq!("2.4", dec.to_string());
2995
2996    let mut dec = UnsignedDecimal::from_str("2.45").unwrap();
2997    dec.round_with_mode(-1, UnsignedRoundingMode::HalfExpand);
2998    assert_eq!("2.5", dec.to_string());
2999
3000    let mut dec = UnsignedDecimal::from_str("22.222").unwrap();
3001    dec.round_with_mode(-2, UnsignedRoundingMode::HalfExpand);
3002    assert_eq!("22.22", dec.to_string());
3003
3004    let mut dec = UnsignedDecimal::from_str("99.999").unwrap();
3005    dec.round_with_mode(-2, UnsignedRoundingMode::HalfExpand);
3006    assert_eq!("100.00", dec.to_string());
3007
3008    let mut dec = UnsignedDecimal::from_str("99.999").unwrap();
3009    dec.round_with_mode(-5, UnsignedRoundingMode::HalfExpand);
3010    assert_eq!("99.99900", dec.to_string());
3011
3012    let mut dec = UnsignedDecimal::from_str("99.999").unwrap();
3013    dec.round_with_mode(4, UnsignedRoundingMode::HalfExpand);
3014    assert_eq!("0000", dec.to_string());
3015
3016    let mut dec = UnsignedDecimal::from_str("0.009").unwrap();
3017    dec.round_with_mode(-1, UnsignedRoundingMode::HalfExpand);
3018    assert_eq!("0.0", dec.to_string());
3019
3020    // Test specific cases
3021    let mut dec = UnsignedDecimal::from_str("1.108").unwrap();
3022    dec.round_with_mode(-2, UnsignedRoundingMode::HalfEven);
3023    assert_eq!("1.11", dec.to_string());
3024
3025    let mut dec = UnsignedDecimal::from_str("1.108").unwrap();
3026    dec.expand(-2);
3027    assert_eq!("1.11", dec.to_string());
3028
3029    let mut dec = UnsignedDecimal::from_str("1.108").unwrap();
3030    dec.trunc(-2);
3031    assert_eq!("1.10", dec.to_string());
3032
3033    let mut dec = UnsignedDecimal::from_str("2.78536913177").unwrap();
3034    dec.round_with_mode(-2, UnsignedRoundingMode::HalfEven);
3035    assert_eq!("2.79", dec.to_string());
3036}
3037
3038#[test]
3039fn test_concatenate() {
3040    #[derive(Debug)]
3041    struct TestCase {
3042        pub input_1: &'static str,
3043        pub input_2: &'static str,
3044        pub expected: Option<&'static str>,
3045    }
3046    let cases = [
3047        TestCase {
3048            input_1: "123",
3049            input_2: "0.456",
3050            expected: Some("123.456"),
3051        },
3052        TestCase {
3053            input_1: "0.456",
3054            input_2: "123",
3055            expected: None,
3056        },
3057        TestCase {
3058            input_1: "123",
3059            input_2: "0.0456",
3060            expected: Some("123.0456"),
3061        },
3062        TestCase {
3063            input_1: "0.0456",
3064            input_2: "123",
3065            expected: None,
3066        },
3067        TestCase {
3068            input_1: "100",
3069            input_2: "0.456",
3070            expected: Some("100.456"),
3071        },
3072        TestCase {
3073            input_1: "0.456",
3074            input_2: "100",
3075            expected: None,
3076        },
3077        TestCase {
3078            input_1: "100",
3079            input_2: "0.001",
3080            expected: Some("100.001"),
3081        },
3082        TestCase {
3083            input_1: "0.001",
3084            input_2: "100",
3085            expected: None,
3086        },
3087        TestCase {
3088            input_1: "123000",
3089            input_2: "456",
3090            expected: Some("123456"),
3091        },
3092        TestCase {
3093            input_1: "456",
3094            input_2: "123000",
3095            expected: None,
3096        },
3097        TestCase {
3098            input_1: "5",
3099            input_2: "5",
3100            expected: None,
3101        },
3102        TestCase {
3103            input_1: "120",
3104            input_2: "25",
3105            expected: None,
3106        },
3107        TestCase {
3108            input_1: "1.1",
3109            input_2: "0.2",
3110            expected: None,
3111        },
3112        TestCase {
3113            input_1: "0",
3114            input_2: "222",
3115            expected: Some("222"),
3116        },
3117        TestCase {
3118            input_1: "222",
3119            input_2: "0",
3120            expected: Some("222"),
3121        },
3122        TestCase {
3123            input_1: "0",
3124            input_2: "0",
3125            expected: Some("0"),
3126        },
3127        TestCase {
3128            input_1: "000",
3129            input_2: "0",
3130            expected: Some("000"),
3131        },
3132        TestCase {
3133            input_1: "0.00",
3134            input_2: "0",
3135            expected: Some("0.00"),
3136        },
3137    ];
3138    for cas in &cases {
3139        let fd1 = UnsignedDecimal::from_str(cas.input_1).unwrap();
3140        let fd2 = UnsignedDecimal::from_str(cas.input_2).unwrap();
3141        match fd1.concatenated_end(fd2) {
3142            Ok(fd) => {
3143                assert_eq!(cas.expected, Some(fd.to_string().as_str()), "{cas:?}");
3144            }
3145            Err(_) => {
3146                assert!(cas.expected.is_none(), "{cas:?}");
3147            }
3148        }
3149    }
3150}
3151
3152#[test]
3153fn test_rounding_increment() {
3154    // Test Truncate Right
3155    let mut dec = UnsignedDecimal::from(4235970u32).multiplied_pow10(-3);
3156    assert_eq!("4235.970", dec.to_string());
3157
3158    dec.round_with_mode_and_increment(
3159        -2,
3160        UnsignedRoundingMode::Trunc,
3161        RoundingIncrement::MultiplesOf2,
3162    );
3163    assert_eq!("4235.96", dec.to_string());
3164
3165    dec.round_with_mode_and_increment(
3166        -1,
3167        UnsignedRoundingMode::Trunc,
3168        RoundingIncrement::MultiplesOf5,
3169    );
3170    assert_eq!("4235.5", dec.to_string());
3171
3172    dec.round_with_mode_and_increment(
3173        0,
3174        UnsignedRoundingMode::Trunc,
3175        RoundingIncrement::MultiplesOf25,
3176    );
3177    assert_eq!("4225", dec.to_string());
3178
3179    dec.round_with_mode_and_increment(
3180        5,
3181        UnsignedRoundingMode::Trunc,
3182        RoundingIncrement::MultiplesOf5,
3183    );
3184    assert_eq!("00000", dec.to_string());
3185
3186    dec.round_with_mode_and_increment(
3187        2,
3188        UnsignedRoundingMode::Trunc,
3189        RoundingIncrement::MultiplesOf2,
3190    );
3191    assert_eq!("00000", dec.to_string());
3192
3193    let mut dec = UnsignedDecimal::from_str("1234.56").unwrap();
3194    dec.round_with_mode_and_increment(
3195        -1,
3196        UnsignedRoundingMode::Trunc,
3197        RoundingIncrement::MultiplesOf2,
3198    );
3199    assert_eq!("1234.4", dec.to_string());
3200
3201    let mut dec = UnsignedDecimal::from_str("0.009").unwrap();
3202    dec.round_with_mode_and_increment(
3203        -1,
3204        UnsignedRoundingMode::Trunc,
3205        RoundingIncrement::MultiplesOf5,
3206    );
3207    assert_eq!("0.0", dec.to_string());
3208
3209    let mut dec = UnsignedDecimal::from_str("0.60").unwrap();
3210    dec.round_with_mode_and_increment(
3211        -2,
3212        UnsignedRoundingMode::Trunc,
3213        RoundingIncrement::MultiplesOf25,
3214    );
3215    assert_eq!("0.50", dec.to_string());
3216
3217    let mut dec = UnsignedDecimal::from_str("0.40").unwrap();
3218    dec.round_with_mode_and_increment(
3219        -2,
3220        UnsignedRoundingMode::Trunc,
3221        RoundingIncrement::MultiplesOf25,
3222    );
3223    assert_eq!("0.25", dec.to_string());
3224
3225    let mut dec = UnsignedDecimal::from_str("0.7000000099").unwrap();
3226    dec.round_with_mode_and_increment(
3227        -3,
3228        UnsignedRoundingMode::Trunc,
3229        RoundingIncrement::MultiplesOf2,
3230    );
3231    assert_eq!("0.700", dec.to_string());
3232
3233    let mut dec = UnsignedDecimal::from_str("5").unwrap();
3234    dec.round_with_mode_and_increment(
3235        0,
3236        UnsignedRoundingMode::Trunc,
3237        RoundingIncrement::MultiplesOf25,
3238    );
3239    assert_eq!("0", dec.to_string());
3240
3241    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MIN);
3242    dec.round_with_mode_and_increment(
3243        i16::MIN,
3244        UnsignedRoundingMode::Trunc,
3245        RoundingIncrement::MultiplesOf2,
3246    );
3247    assert_eq!(UnsignedDecimal::from(6u32).multiplied_pow10(i16::MIN), dec);
3248
3249    let mut dec = UnsignedDecimal::from(9u32).multiplied_pow10(i16::MIN);
3250    dec.round_with_mode_and_increment(
3251        i16::MIN,
3252        UnsignedRoundingMode::Trunc,
3253        RoundingIncrement::MultiplesOf5,
3254    );
3255    assert_eq!(UnsignedDecimal::from(5u32).multiplied_pow10(i16::MIN), dec);
3256
3257    let mut dec = UnsignedDecimal::from(70u32).multiplied_pow10(i16::MIN);
3258    dec.round_with_mode_and_increment(
3259        i16::MIN,
3260        UnsignedRoundingMode::Trunc,
3261        RoundingIncrement::MultiplesOf25,
3262    );
3263    assert_eq!(UnsignedDecimal::from(50u32).multiplied_pow10(i16::MIN), dec);
3264
3265    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MAX);
3266    dec.round_with_mode_and_increment(
3267        i16::MAX,
3268        UnsignedRoundingMode::Trunc,
3269        RoundingIncrement::MultiplesOf2,
3270    );
3271    assert_eq!(UnsignedDecimal::from(6u32).multiplied_pow10(i16::MAX), dec);
3272
3273    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MAX);
3274    dec.round_with_mode_and_increment(
3275        i16::MAX,
3276        UnsignedRoundingMode::Trunc,
3277        RoundingIncrement::MultiplesOf5,
3278    );
3279    assert_eq!(UnsignedDecimal::from(5u32).multiplied_pow10(i16::MAX), dec);
3280
3281    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MAX);
3282    dec.round_with_mode_and_increment(
3283        i16::MAX,
3284        UnsignedRoundingMode::Trunc,
3285        RoundingIncrement::MultiplesOf25,
3286    );
3287    assert_eq!(UnsignedDecimal::from(0u32).multiplied_pow10(i16::MAX), dec);
3288
3289    // Test Expand
3290    let mut dec = UnsignedDecimal::from(4235970u32).multiplied_pow10(-3);
3291    assert_eq!("4235.970", dec.to_string());
3292
3293    dec.round_with_mode_and_increment(
3294        -2,
3295        UnsignedRoundingMode::Expand,
3296        RoundingIncrement::MultiplesOf2,
3297    );
3298    assert_eq!("4235.98", dec.to_string());
3299
3300    dec.round_with_mode_and_increment(
3301        -1,
3302        UnsignedRoundingMode::Expand,
3303        RoundingIncrement::MultiplesOf5,
3304    );
3305    assert_eq!("4236.0", dec.to_string());
3306
3307    dec.round_with_mode_and_increment(
3308        0,
3309        UnsignedRoundingMode::Expand,
3310        RoundingIncrement::MultiplesOf25,
3311    );
3312    assert_eq!("4250", dec.to_string());
3313
3314    dec.round_with_mode_and_increment(
3315        5,
3316        UnsignedRoundingMode::Expand,
3317        RoundingIncrement::MultiplesOf5,
3318    );
3319    assert_eq!("500000", dec.to_string());
3320
3321    dec.round_with_mode_and_increment(
3322        2,
3323        UnsignedRoundingMode::Expand,
3324        RoundingIncrement::MultiplesOf2,
3325    );
3326    assert_eq!("500000", dec.to_string());
3327
3328    let mut dec = UnsignedDecimal::from_str("1234.56").unwrap();
3329    dec.round_with_mode_and_increment(
3330        -1,
3331        UnsignedRoundingMode::Expand,
3332        RoundingIncrement::MultiplesOf2,
3333    );
3334    assert_eq!("1234.6", dec.to_string());
3335
3336    let mut dec = UnsignedDecimal::from_str("0.009").unwrap();
3337    dec.round_with_mode_and_increment(
3338        -1,
3339        UnsignedRoundingMode::Expand,
3340        RoundingIncrement::MultiplesOf5,
3341    );
3342    assert_eq!("0.5", dec.to_string());
3343
3344    let mut dec = UnsignedDecimal::from_str("0.60").unwrap();
3345    dec.round_with_mode_and_increment(
3346        -2,
3347        UnsignedRoundingMode::Expand,
3348        RoundingIncrement::MultiplesOf25,
3349    );
3350    assert_eq!("0.75", dec.to_string());
3351
3352    let mut dec = UnsignedDecimal::from_str("0.40").unwrap();
3353    dec.round_with_mode_and_increment(
3354        -2,
3355        UnsignedRoundingMode::Expand,
3356        RoundingIncrement::MultiplesOf25,
3357    );
3358    assert_eq!("0.50", dec.to_string());
3359
3360    let mut dec = UnsignedDecimal::from_str("0.7000000099").unwrap();
3361    dec.round_with_mode_and_increment(
3362        -3,
3363        UnsignedRoundingMode::Expand,
3364        RoundingIncrement::MultiplesOf2,
3365    );
3366    assert_eq!("0.702", dec.to_string());
3367
3368    let mut dec = UnsignedDecimal::from_str("5").unwrap();
3369    dec.round_with_mode_and_increment(
3370        0,
3371        UnsignedRoundingMode::Expand,
3372        RoundingIncrement::MultiplesOf25,
3373    );
3374    assert_eq!("25", dec.to_string());
3375
3376    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MIN);
3377    dec.round_with_mode_and_increment(
3378        i16::MIN,
3379        UnsignedRoundingMode::Expand,
3380        RoundingIncrement::MultiplesOf2,
3381    );
3382    assert_eq!(UnsignedDecimal::from(8u32).multiplied_pow10(i16::MIN), dec);
3383
3384    let mut dec = UnsignedDecimal::from(9u32).multiplied_pow10(i16::MIN);
3385    dec.round_with_mode_and_increment(
3386        i16::MIN,
3387        UnsignedRoundingMode::Expand,
3388        RoundingIncrement::MultiplesOf5,
3389    );
3390    assert_eq!(UnsignedDecimal::from(10u32).multiplied_pow10(i16::MIN), dec);
3391
3392    let mut dec = UnsignedDecimal::from(70u32).multiplied_pow10(i16::MIN);
3393    dec.round_with_mode_and_increment(
3394        i16::MIN,
3395        UnsignedRoundingMode::Expand,
3396        RoundingIncrement::MultiplesOf25,
3397    );
3398    assert_eq!(UnsignedDecimal::from(75u32).multiplied_pow10(i16::MIN), dec);
3399
3400    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MAX);
3401    dec.round_with_mode_and_increment(
3402        i16::MAX,
3403        UnsignedRoundingMode::Expand,
3404        RoundingIncrement::MultiplesOf2,
3405    );
3406    assert_eq!(UnsignedDecimal::from(8u32).multiplied_pow10(i16::MAX), dec);
3407
3408    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MAX);
3409    dec.round_with_mode_and_increment(
3410        i16::MAX,
3411        UnsignedRoundingMode::Expand,
3412        RoundingIncrement::MultiplesOf5,
3413    );
3414    assert_eq!(UnsignedDecimal::from(0u32).multiplied_pow10(i16::MAX), dec);
3415
3416    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MAX);
3417    dec.round_with_mode_and_increment(
3418        i16::MAX,
3419        UnsignedRoundingMode::Expand,
3420        RoundingIncrement::MultiplesOf25,
3421    );
3422    assert_eq!(UnsignedDecimal::from(0u32).multiplied_pow10(i16::MAX), dec);
3423
3424    // Test Half Truncate Right
3425    let mut dec = UnsignedDecimal::from(4235970u32).multiplied_pow10(-3);
3426    assert_eq!("4235.970", dec.to_string());
3427
3428    dec.round_with_mode_and_increment(
3429        -2,
3430        UnsignedRoundingMode::HalfTrunc,
3431        RoundingIncrement::MultiplesOf2,
3432    );
3433    assert_eq!("4235.96", dec.to_string());
3434
3435    dec.round_with_mode_and_increment(
3436        -1,
3437        UnsignedRoundingMode::HalfTrunc,
3438        RoundingIncrement::MultiplesOf5,
3439    );
3440    assert_eq!("4236.0", dec.to_string());
3441
3442    dec.round_with_mode_and_increment(
3443        0,
3444        UnsignedRoundingMode::HalfTrunc,
3445        RoundingIncrement::MultiplesOf25,
3446    );
3447    assert_eq!("4225", dec.to_string());
3448
3449    dec.round_with_mode_and_increment(
3450        5,
3451        UnsignedRoundingMode::HalfTrunc,
3452        RoundingIncrement::MultiplesOf5,
3453    );
3454    assert_eq!("00000", dec.to_string());
3455
3456    dec.round_with_mode_and_increment(
3457        2,
3458        UnsignedRoundingMode::HalfTrunc,
3459        RoundingIncrement::MultiplesOf2,
3460    );
3461    assert_eq!("00000", dec.to_string());
3462
3463    let mut dec = UnsignedDecimal::from_str("1234.56").unwrap();
3464    dec.round_with_mode_and_increment(
3465        -1,
3466        UnsignedRoundingMode::HalfTrunc,
3467        RoundingIncrement::MultiplesOf2,
3468    );
3469    assert_eq!("1234.6", dec.to_string());
3470
3471    let mut dec = UnsignedDecimal::from_str("0.009").unwrap();
3472    dec.round_with_mode_and_increment(
3473        -1,
3474        UnsignedRoundingMode::HalfTrunc,
3475        RoundingIncrement::MultiplesOf5,
3476    );
3477    assert_eq!("0.0", dec.to_string());
3478
3479    let mut dec = UnsignedDecimal::from_str("0.60").unwrap();
3480    dec.round_with_mode_and_increment(
3481        -2,
3482        UnsignedRoundingMode::HalfTrunc,
3483        RoundingIncrement::MultiplesOf25,
3484    );
3485    assert_eq!("0.50", dec.to_string());
3486
3487    let mut dec = UnsignedDecimal::from_str("0.40").unwrap();
3488    dec.round_with_mode_and_increment(
3489        -2,
3490        UnsignedRoundingMode::HalfTrunc,
3491        RoundingIncrement::MultiplesOf25,
3492    );
3493    assert_eq!("0.50", dec.to_string());
3494
3495    let mut dec = UnsignedDecimal::from_str("0.7000000099").unwrap();
3496    dec.round_with_mode_and_increment(
3497        -3,
3498        UnsignedRoundingMode::HalfTrunc,
3499        RoundingIncrement::MultiplesOf2,
3500    );
3501    assert_eq!("0.700", dec.to_string());
3502
3503    let mut dec = UnsignedDecimal::from_str("5").unwrap();
3504    dec.round_with_mode_and_increment(
3505        0,
3506        UnsignedRoundingMode::HalfTrunc,
3507        RoundingIncrement::MultiplesOf25,
3508    );
3509    assert_eq!("0", dec.to_string());
3510
3511    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MIN);
3512    dec.round_with_mode_and_increment(
3513        i16::MIN,
3514        UnsignedRoundingMode::HalfTrunc,
3515        RoundingIncrement::MultiplesOf2,
3516    );
3517    assert_eq!(UnsignedDecimal::from(6u32).multiplied_pow10(i16::MIN), dec);
3518
3519    let mut dec = UnsignedDecimal::from(9u32).multiplied_pow10(i16::MIN);
3520    dec.round_with_mode_and_increment(
3521        i16::MIN,
3522        UnsignedRoundingMode::HalfTrunc,
3523        RoundingIncrement::MultiplesOf5,
3524    );
3525    assert_eq!(UnsignedDecimal::from(10u32).multiplied_pow10(i16::MIN), dec);
3526
3527    let mut dec = UnsignedDecimal::from(70u32).multiplied_pow10(i16::MIN);
3528    dec.round_with_mode_and_increment(
3529        i16::MIN,
3530        UnsignedRoundingMode::HalfTrunc,
3531        RoundingIncrement::MultiplesOf25,
3532    );
3533    assert_eq!(UnsignedDecimal::from(75u32).multiplied_pow10(i16::MIN), dec);
3534
3535    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MAX);
3536    dec.round_with_mode_and_increment(
3537        i16::MAX,
3538        UnsignedRoundingMode::HalfTrunc,
3539        RoundingIncrement::MultiplesOf2,
3540    );
3541    assert_eq!(UnsignedDecimal::from(6u32).multiplied_pow10(i16::MAX), dec);
3542
3543    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MAX);
3544    dec.round_with_mode_and_increment(
3545        i16::MAX,
3546        UnsignedRoundingMode::HalfTrunc,
3547        RoundingIncrement::MultiplesOf5,
3548    );
3549    assert_eq!(UnsignedDecimal::from(5u32).multiplied_pow10(i16::MAX), dec);
3550
3551    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MAX);
3552    dec.round_with_mode_and_increment(
3553        i16::MAX,
3554        UnsignedRoundingMode::HalfTrunc,
3555        RoundingIncrement::MultiplesOf25,
3556    );
3557    assert_eq!(UnsignedDecimal::from(0u32).multiplied_pow10(i16::MAX), dec);
3558
3559    // Test Half Expand
3560    let mut dec = UnsignedDecimal::from(4235970u32).multiplied_pow10(-3);
3561    assert_eq!("4235.970", dec.to_string());
3562
3563    dec.round_with_mode_and_increment(
3564        -2,
3565        UnsignedRoundingMode::HalfExpand,
3566        RoundingIncrement::MultiplesOf2,
3567    );
3568    assert_eq!("4235.98", dec.to_string());
3569
3570    dec.round_with_mode_and_increment(
3571        -1,
3572        UnsignedRoundingMode::HalfExpand,
3573        RoundingIncrement::MultiplesOf5,
3574    );
3575    assert_eq!("4236.0", dec.to_string());
3576
3577    dec.round_with_mode_and_increment(
3578        0,
3579        UnsignedRoundingMode::HalfExpand,
3580        RoundingIncrement::MultiplesOf25,
3581    );
3582    assert_eq!("4225", dec.to_string());
3583
3584    dec.round_with_mode_and_increment(
3585        5,
3586        UnsignedRoundingMode::HalfExpand,
3587        RoundingIncrement::MultiplesOf5,
3588    );
3589    assert_eq!("00000", dec.to_string());
3590
3591    dec.round_with_mode_and_increment(
3592        2,
3593        UnsignedRoundingMode::HalfExpand,
3594        RoundingIncrement::MultiplesOf2,
3595    );
3596    assert_eq!("00000", dec.to_string());
3597
3598    let mut dec = UnsignedDecimal::from_str("1234.56").unwrap();
3599    dec.round_with_mode_and_increment(
3600        -1,
3601        UnsignedRoundingMode::HalfExpand,
3602        RoundingIncrement::MultiplesOf2,
3603    );
3604    assert_eq!("1234.6", dec.to_string());
3605
3606    let mut dec = UnsignedDecimal::from_str("0.009").unwrap();
3607    dec.round_with_mode_and_increment(
3608        -1,
3609        UnsignedRoundingMode::HalfExpand,
3610        RoundingIncrement::MultiplesOf5,
3611    );
3612    assert_eq!("0.0", dec.to_string());
3613
3614    let mut dec = UnsignedDecimal::from_str("0.60").unwrap();
3615    dec.round_with_mode_and_increment(
3616        -2,
3617        UnsignedRoundingMode::HalfExpand,
3618        RoundingIncrement::MultiplesOf25,
3619    );
3620    assert_eq!("0.50", dec.to_string());
3621
3622    let mut dec = UnsignedDecimal::from_str("0.40").unwrap();
3623    dec.round_with_mode_and_increment(
3624        -2,
3625        UnsignedRoundingMode::HalfExpand,
3626        RoundingIncrement::MultiplesOf25,
3627    );
3628    assert_eq!("0.50", dec.to_string());
3629
3630    let mut dec = UnsignedDecimal::from_str("0.7000000099").unwrap();
3631    dec.round_with_mode_and_increment(
3632        -3,
3633        UnsignedRoundingMode::HalfExpand,
3634        RoundingIncrement::MultiplesOf2,
3635    );
3636    assert_eq!("0.700", dec.to_string());
3637
3638    let mut dec = UnsignedDecimal::from_str("5").unwrap();
3639    dec.round_with_mode_and_increment(
3640        0,
3641        UnsignedRoundingMode::HalfExpand,
3642        RoundingIncrement::MultiplesOf25,
3643    );
3644    assert_eq!("0", dec.to_string());
3645
3646    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MIN);
3647    dec.round_with_mode_and_increment(
3648        i16::MIN,
3649        UnsignedRoundingMode::HalfExpand,
3650        RoundingIncrement::MultiplesOf2,
3651    );
3652    assert_eq!(UnsignedDecimal::from(8u32).multiplied_pow10(i16::MIN), dec);
3653
3654    let mut dec = UnsignedDecimal::from(9u32).multiplied_pow10(i16::MIN);
3655    dec.round_with_mode_and_increment(
3656        i16::MIN,
3657        UnsignedRoundingMode::HalfExpand,
3658        RoundingIncrement::MultiplesOf5,
3659    );
3660    assert_eq!(UnsignedDecimal::from(10u32).multiplied_pow10(i16::MIN), dec);
3661
3662    let mut dec = UnsignedDecimal::from(70u32).multiplied_pow10(i16::MIN);
3663    dec.round_with_mode_and_increment(
3664        i16::MIN,
3665        UnsignedRoundingMode::HalfExpand,
3666        RoundingIncrement::MultiplesOf25,
3667    );
3668    assert_eq!(UnsignedDecimal::from(75u32).multiplied_pow10(i16::MIN), dec);
3669
3670    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MAX);
3671    dec.round_with_mode_and_increment(
3672        i16::MAX,
3673        UnsignedRoundingMode::HalfExpand,
3674        RoundingIncrement::MultiplesOf2,
3675    );
3676    assert_eq!(UnsignedDecimal::from(8u32).multiplied_pow10(i16::MAX), dec);
3677
3678    // Test Half Even
3679    let mut dec = UnsignedDecimal::from(4235970u32).multiplied_pow10(-3);
3680    assert_eq!("4235.970", dec.to_string());
3681
3682    dec.round_with_mode_and_increment(
3683        -2,
3684        UnsignedRoundingMode::HalfEven,
3685        RoundingIncrement::MultiplesOf2,
3686    );
3687    assert_eq!("4235.96", dec.to_string());
3688
3689    dec.round_with_mode_and_increment(
3690        -1,
3691        UnsignedRoundingMode::HalfEven,
3692        RoundingIncrement::MultiplesOf5,
3693    );
3694    assert_eq!("4236.0", dec.to_string());
3695
3696    dec.round_with_mode_and_increment(
3697        0,
3698        UnsignedRoundingMode::HalfEven,
3699        RoundingIncrement::MultiplesOf25,
3700    );
3701    assert_eq!("4225", dec.to_string());
3702
3703    dec.round_with_mode_and_increment(
3704        5,
3705        UnsignedRoundingMode::HalfEven,
3706        RoundingIncrement::MultiplesOf5,
3707    );
3708    assert_eq!("00000", dec.to_string());
3709
3710    dec.round_with_mode_and_increment(
3711        2,
3712        UnsignedRoundingMode::HalfEven,
3713        RoundingIncrement::MultiplesOf2,
3714    );
3715    assert_eq!("00000", dec.to_string());
3716
3717    let mut dec = UnsignedDecimal::from_str("1234.56").unwrap();
3718    dec.round_with_mode_and_increment(
3719        -1,
3720        UnsignedRoundingMode::HalfEven,
3721        RoundingIncrement::MultiplesOf2,
3722    );
3723    assert_eq!("1234.6", dec.to_string());
3724
3725    let mut dec = UnsignedDecimal::from_str("0.009").unwrap();
3726    dec.round_with_mode_and_increment(
3727        -1,
3728        UnsignedRoundingMode::HalfEven,
3729        RoundingIncrement::MultiplesOf5,
3730    );
3731    assert_eq!("0.0", dec.to_string());
3732
3733    let mut dec = UnsignedDecimal::from_str("0.60").unwrap();
3734    dec.round_with_mode_and_increment(
3735        -2,
3736        UnsignedRoundingMode::HalfEven,
3737        RoundingIncrement::MultiplesOf25,
3738    );
3739    assert_eq!("0.50", dec.to_string());
3740
3741    let mut dec = UnsignedDecimal::from_str("0.40").unwrap();
3742    dec.round_with_mode_and_increment(
3743        -2,
3744        UnsignedRoundingMode::HalfEven,
3745        RoundingIncrement::MultiplesOf25,
3746    );
3747    assert_eq!("0.50", dec.to_string());
3748
3749    let mut dec = UnsignedDecimal::from_str("0.7000000099").unwrap();
3750    dec.round_with_mode_and_increment(
3751        -3,
3752        UnsignedRoundingMode::HalfEven,
3753        RoundingIncrement::MultiplesOf2,
3754    );
3755    assert_eq!("0.700", dec.to_string());
3756
3757    let mut dec = UnsignedDecimal::from_str("5").unwrap();
3758    dec.round_with_mode_and_increment(
3759        0,
3760        UnsignedRoundingMode::HalfEven,
3761        RoundingIncrement::MultiplesOf25,
3762    );
3763    assert_eq!("0", dec.to_string());
3764
3765    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MIN);
3766    dec.round_with_mode_and_increment(
3767        i16::MIN,
3768        UnsignedRoundingMode::HalfEven,
3769        RoundingIncrement::MultiplesOf2,
3770    );
3771    assert_eq!(UnsignedDecimal::from(8u32).multiplied_pow10(i16::MIN), dec);
3772
3773    let mut dec = UnsignedDecimal::from(9u32).multiplied_pow10(i16::MIN);
3774    dec.round_with_mode_and_increment(
3775        i16::MIN,
3776        UnsignedRoundingMode::HalfEven,
3777        RoundingIncrement::MultiplesOf5,
3778    );
3779    assert_eq!(UnsignedDecimal::from(10u32).multiplied_pow10(i16::MIN), dec);
3780
3781    let mut dec = UnsignedDecimal::from(70u32).multiplied_pow10(i16::MIN);
3782    dec.round_with_mode_and_increment(
3783        i16::MIN,
3784        UnsignedRoundingMode::HalfEven,
3785        RoundingIncrement::MultiplesOf25,
3786    );
3787    assert_eq!(UnsignedDecimal::from(75u32).multiplied_pow10(i16::MIN), dec);
3788
3789    let mut dec = UnsignedDecimal::from(7u32).multiplied_pow10(i16::MAX);
3790    dec.round_with_mode_and_increment(
3791        i16::MAX,
3792        UnsignedRoundingMode::HalfEven,
3793        RoundingIncrement::MultiplesOf2,
3794    );
3795    assert_eq!(UnsignedDecimal::from(8u32).multiplied_pow10(i16::MAX), dec);
3796
3797    // Test specific cases
3798    let mut dec = UnsignedDecimal::from_str("1.108").unwrap();
3799    dec.round_with_mode_and_increment(
3800        -2,
3801        UnsignedRoundingMode::Expand,
3802        RoundingIncrement::MultiplesOf2,
3803    );
3804    assert_eq!("1.12", dec.to_string());
3805
3806    let mut dec = UnsignedDecimal::from_str("1.108").unwrap();
3807    dec.round_with_mode_and_increment(
3808        -2,
3809        UnsignedRoundingMode::Expand,
3810        RoundingIncrement::MultiplesOf5,
3811    );
3812    assert_eq!("1.15", dec.to_string());
3813
3814    let mut dec = UnsignedDecimal::from_str("1.108").unwrap();
3815    dec.round_with_mode_and_increment(
3816        -2,
3817        UnsignedRoundingMode::Expand,
3818        RoundingIncrement::MultiplesOf25,
3819    );
3820    assert_eq!("1.25", dec.to_string());
3821
3822    let mut dec = UnsignedDecimal::from(9u32).multiplied_pow10(i16::MAX - 1);
3823    dec.round_with_mode_and_increment(
3824        i16::MAX - 1,
3825        UnsignedRoundingMode::Expand,
3826        RoundingIncrement::MultiplesOf25,
3827    );
3828    assert_eq!(
3829        UnsignedDecimal::from(25u32).multiplied_pow10(i16::MAX - 1),
3830        dec
3831    );
3832
3833    let mut dec = UnsignedDecimal::from(9u32).multiplied_pow10(i16::MAX);
3834    dec.round_with_mode_and_increment(
3835        i16::MAX,
3836        UnsignedRoundingMode::Expand,
3837        RoundingIncrement::MultiplesOf25,
3838    );
3839    assert_eq!(UnsignedDecimal::from(0u32).multiplied_pow10(i16::MAX), dec);
3840
3841    let mut dec = UnsignedDecimal::from_str("0").unwrap();
3842    dec.round_with_mode_and_increment(
3843        0,
3844        UnsignedRoundingMode::Expand,
3845        RoundingIncrement::MultiplesOf2,
3846    );
3847    assert_eq!("0", dec.to_string());
3848
3849    let mut dec = UnsignedDecimal::from_str("0").unwrap();
3850    dec.round_with_mode_and_increment(
3851        0,
3852        UnsignedRoundingMode::Expand,
3853        RoundingIncrement::MultiplesOf5,
3854    );
3855    assert_eq!("0", dec.to_string());
3856
3857    let mut dec = UnsignedDecimal::from_str("0").unwrap();
3858    dec.round_with_mode_and_increment(
3859        0,
3860        UnsignedRoundingMode::Expand,
3861        RoundingIncrement::MultiplesOf25,
3862    );
3863    assert_eq!("0", dec.to_string());
3864
3865    let mut dec = UnsignedDecimal::from_str("0.1").unwrap();
3866    dec.round_with_mode_and_increment(
3867        0,
3868        UnsignedRoundingMode::Expand,
3869        RoundingIncrement::MultiplesOf2,
3870    );
3871    assert_eq!("2", dec.to_string());
3872
3873    let mut dec = UnsignedDecimal::from_str("0.1").unwrap();
3874    dec.round_with_mode_and_increment(
3875        0,
3876        UnsignedRoundingMode::Expand,
3877        RoundingIncrement::MultiplesOf5,
3878    );
3879    assert_eq!("5", dec.to_string());
3880
3881    let mut dec = UnsignedDecimal::from_str("0.1").unwrap();
3882    dec.round_with_mode_and_increment(
3883        0,
3884        UnsignedRoundingMode::Expand,
3885        RoundingIncrement::MultiplesOf25,
3886    );
3887    assert_eq!("25", dec.to_string());
3888
3889    let mut dec = UnsignedDecimal::from_str("1").unwrap();
3890    dec.round_with_mode_and_increment(
3891        0,
3892        UnsignedRoundingMode::Expand,
3893        RoundingIncrement::MultiplesOf2,
3894    );
3895    assert_eq!("2", dec.to_string());
3896
3897    let mut dec = UnsignedDecimal::from_str("1").unwrap();
3898    dec.round_with_mode_and_increment(
3899        0,
3900        UnsignedRoundingMode::Expand,
3901        RoundingIncrement::MultiplesOf5,
3902    );
3903    assert_eq!("5", dec.to_string());
3904
3905    let mut dec = UnsignedDecimal::from_str("1").unwrap();
3906    dec.round_with_mode_and_increment(
3907        0,
3908        UnsignedRoundingMode::Expand,
3909        RoundingIncrement::MultiplesOf25,
3910    );
3911    assert_eq!("25", dec.to_string());
3912
3913    let mut dec = UnsignedDecimal::from_str("2").unwrap();
3914    dec.round_with_mode_and_increment(
3915        0,
3916        UnsignedRoundingMode::Expand,
3917        RoundingIncrement::MultiplesOf2,
3918    );
3919    assert_eq!("2", dec.to_string());
3920
3921    let mut dec = UnsignedDecimal::from_str("2").unwrap();
3922    dec.round_with_mode_and_increment(
3923        0,
3924        UnsignedRoundingMode::Expand,
3925        RoundingIncrement::MultiplesOf5,
3926    );
3927    assert_eq!("5", dec.to_string());
3928
3929    let mut dec = UnsignedDecimal::from_str("2.1").unwrap();
3930    dec.round_with_mode_and_increment(
3931        0,
3932        UnsignedRoundingMode::Expand,
3933        RoundingIncrement::MultiplesOf2,
3934    );
3935    assert_eq!("4", dec.to_string());
3936
3937    let mut dec = UnsignedDecimal::from_str("2.1").unwrap();
3938    dec.round_with_mode_and_increment(
3939        0,
3940        UnsignedRoundingMode::Expand,
3941        RoundingIncrement::MultiplesOf5,
3942    );
3943    assert_eq!("5", dec.to_string());
3944
3945    let mut dec = UnsignedDecimal::from_str("4").unwrap();
3946    dec.round_with_mode_and_increment(
3947        0,
3948        UnsignedRoundingMode::Expand,
3949        RoundingIncrement::MultiplesOf2,
3950    );
3951    assert_eq!("4", dec.to_string());
3952
3953    let mut dec = UnsignedDecimal::from_str("4").unwrap();
3954    dec.round_with_mode_and_increment(
3955        0,
3956        UnsignedRoundingMode::Expand,
3957        RoundingIncrement::MultiplesOf5,
3958    );
3959    assert_eq!("5", dec.to_string());
3960
3961    let mut dec = UnsignedDecimal::from_str("4.1").unwrap();
3962    dec.round_with_mode_and_increment(
3963        0,
3964        UnsignedRoundingMode::Expand,
3965        RoundingIncrement::MultiplesOf2,
3966    );
3967    assert_eq!("6", dec.to_string());
3968
3969    let mut dec = UnsignedDecimal::from_str("4.1").unwrap();
3970    dec.round_with_mode_and_increment(
3971        0,
3972        UnsignedRoundingMode::Expand,
3973        RoundingIncrement::MultiplesOf5,
3974    );
3975    assert_eq!("5", dec.to_string());
3976
3977    let mut dec = UnsignedDecimal::from_str("5").unwrap();
3978    dec.round_with_mode_and_increment(
3979        0,
3980        UnsignedRoundingMode::Expand,
3981        RoundingIncrement::MultiplesOf2,
3982    );
3983    assert_eq!("6", dec.to_string());
3984
3985    let mut dec = UnsignedDecimal::from_str("5").unwrap();
3986    dec.round_with_mode_and_increment(
3987        0,
3988        UnsignedRoundingMode::Expand,
3989        RoundingIncrement::MultiplesOf5,
3990    );
3991    assert_eq!("5", dec.to_string());
3992
3993    let mut dec = UnsignedDecimal::from_str("5.1").unwrap();
3994    dec.round_with_mode_and_increment(
3995        0,
3996        UnsignedRoundingMode::Expand,
3997        RoundingIncrement::MultiplesOf2,
3998    );
3999    assert_eq!("6", dec.to_string());
4000
4001    let mut dec = UnsignedDecimal::from_str("5.1").unwrap();
4002    dec.round_with_mode_and_increment(
4003        0,
4004        UnsignedRoundingMode::Expand,
4005        RoundingIncrement::MultiplesOf5,
4006    );
4007    assert_eq!("10", dec.to_string());
4008
4009    let mut dec = UnsignedDecimal::from_str("6").unwrap();
4010    dec.round_with_mode_and_increment(
4011        0,
4012        UnsignedRoundingMode::Expand,
4013        RoundingIncrement::MultiplesOf2,
4014    );
4015    assert_eq!("6", dec.to_string());
4016
4017    let mut dec = UnsignedDecimal::from_str("6").unwrap();
4018    dec.round_with_mode_and_increment(
4019        0,
4020        UnsignedRoundingMode::Expand,
4021        RoundingIncrement::MultiplesOf5,
4022    );
4023    assert_eq!("10", dec.to_string());
4024
4025    let mut dec = UnsignedDecimal::from_str("0.50").unwrap();
4026    dec.round_with_mode_and_increment(
4027        -2,
4028        UnsignedRoundingMode::Expand,
4029        RoundingIncrement::MultiplesOf25,
4030    );
4031    assert_eq!("0.50", dec.to_string());
4032
4033    let mut dec = UnsignedDecimal::from_str("1.1025").unwrap();
4034    dec.round_with_mode_and_increment(
4035        -3,
4036        UnsignedRoundingMode::HalfTrunc,
4037        RoundingIncrement::MultiplesOf5,
4038    );
4039    assert_eq!("1.100", dec.to_string());
4040
4041    let mut dec = UnsignedDecimal::from_str("1.10125").unwrap();
4042    dec.round_with_mode_and_increment(
4043        -4,
4044        UnsignedRoundingMode::HalfExpand,
4045        RoundingIncrement::MultiplesOf25,
4046    );
4047    assert_eq!("1.1025", dec.to_string());
4048
4049    let mut dec = UnsignedDecimal::from_str("2.71").unwrap();
4050    dec.round_with_mode_and_increment(
4051        -2,
4052        UnsignedRoundingMode::HalfEven,
4053        RoundingIncrement::MultiplesOf2,
4054    );
4055    assert_eq!("2.72", dec.to_string());
4056
4057    let mut dec = UnsignedDecimal::from_str("2.73").unwrap();
4058    dec.round_with_mode_and_increment(
4059        -2,
4060        UnsignedRoundingMode::HalfEven,
4061        RoundingIncrement::MultiplesOf2,
4062    );
4063    assert_eq!("2.72", dec.to_string());
4064
4065    let mut dec = UnsignedDecimal::from_str("2.75").unwrap();
4066    dec.round_with_mode_and_increment(
4067        -2,
4068        UnsignedRoundingMode::HalfEven,
4069        RoundingIncrement::MultiplesOf2,
4070    );
4071    assert_eq!("2.76", dec.to_string());
4072
4073    let mut dec = UnsignedDecimal::from_str("2.77").unwrap();
4074    dec.round_with_mode_and_increment(
4075        -2,
4076        UnsignedRoundingMode::HalfEven,
4077        RoundingIncrement::MultiplesOf2,
4078    );
4079    assert_eq!("2.76", dec.to_string());
4080
4081    let mut dec = UnsignedDecimal::from_str("2.79").unwrap();
4082    dec.round_with_mode_and_increment(
4083        -2,
4084        UnsignedRoundingMode::HalfEven,
4085        RoundingIncrement::MultiplesOf2,
4086    );
4087    assert_eq!("2.80", dec.to_string());
4088
4089    let mut dec = UnsignedDecimal::from_str("2.41").unwrap();
4090    dec.round_with_mode_and_increment(
4091        -2,
4092        UnsignedRoundingMode::HalfEven,
4093        RoundingIncrement::MultiplesOf2,
4094    );
4095    assert_eq!("2.40", dec.to_string());
4096
4097    let mut dec = UnsignedDecimal::from_str("2.43").unwrap();
4098    dec.round_with_mode_and_increment(
4099        -2,
4100        UnsignedRoundingMode::HalfEven,
4101        RoundingIncrement::MultiplesOf2,
4102    );
4103    assert_eq!("2.44", dec.to_string());
4104
4105    let mut dec = UnsignedDecimal::from_str("2.45").unwrap();
4106    dec.round_with_mode_and_increment(
4107        -2,
4108        UnsignedRoundingMode::HalfEven,
4109        RoundingIncrement::MultiplesOf2,
4110    );
4111    assert_eq!("2.44", dec.to_string());
4112
4113    let mut dec = UnsignedDecimal::from_str("2.47").unwrap();
4114    dec.round_with_mode_and_increment(
4115        -2,
4116        UnsignedRoundingMode::HalfEven,
4117        RoundingIncrement::MultiplesOf2,
4118    );
4119    assert_eq!("2.48", dec.to_string());
4120
4121    let mut dec = UnsignedDecimal::from_str("2.49").unwrap();
4122    dec.round_with_mode_and_increment(
4123        -2,
4124        UnsignedRoundingMode::HalfEven,
4125        RoundingIncrement::MultiplesOf2,
4126    );
4127    assert_eq!("2.48", dec.to_string());
4128
4129    let mut dec = UnsignedDecimal::from_str("2.725").unwrap();
4130    dec.round_with_mode_and_increment(
4131        -2,
4132        UnsignedRoundingMode::HalfEven,
4133        RoundingIncrement::MultiplesOf5,
4134    );
4135    assert_eq!("2.70", dec.to_string());
4136
4137    let mut dec = UnsignedDecimal::from_str("2.775").unwrap();
4138    dec.round_with_mode_and_increment(
4139        -2,
4140        UnsignedRoundingMode::HalfEven,
4141        RoundingIncrement::MultiplesOf5,
4142    );
4143    assert_eq!("2.80", dec.to_string());
4144
4145    let mut dec = UnsignedDecimal::from_str("2.875").unwrap();
4146    dec.round_with_mode_and_increment(
4147        -2,
4148        UnsignedRoundingMode::HalfEven,
4149        RoundingIncrement::MultiplesOf25,
4150    );
4151    assert_eq!("3.00", dec.to_string());
4152
4153    let mut dec = UnsignedDecimal::from_str("2.375").unwrap();
4154    dec.round_with_mode_and_increment(
4155        -2,
4156        UnsignedRoundingMode::HalfEven,
4157        RoundingIncrement::MultiplesOf25,
4158    );
4159    assert_eq!("2.50", dec.to_string());
4160
4161    let mut dec = UnsignedDecimal::from_str("2.125").unwrap();
4162    dec.round_with_mode_and_increment(
4163        -2,
4164        UnsignedRoundingMode::HalfEven,
4165        RoundingIncrement::MultiplesOf25,
4166    );
4167    assert_eq!("2.00", dec.to_string());
4168
4169    let mut dec = UnsignedDecimal::from_str("2.625").unwrap();
4170    dec.round_with_mode_and_increment(
4171        -2,
4172        UnsignedRoundingMode::HalfEven,
4173        RoundingIncrement::MultiplesOf25,
4174    );
4175    assert_eq!("2.50", dec.to_string());
4176}