1use crate::{Boolean, Double, Float, Integer, TooLargeForIntegerError};
2use std::fmt;
3use std::fmt::Write;
4use std::str::FromStr;
5
6const DECIMAL_PART_DIGITS: u32 = 18;
7const DECIMAL_PART_POW: i128 = 1_000_000_000_000_000_000;
8const DECIMAL_PART_POW_MINUS_ONE: i128 = 100_000_000_000_000_000;
9
10#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash, Default)]
16#[repr(Rust, packed(8))]
17pub struct Decimal {
18 value: i128, }
20
21impl Decimal {
22 pub const MAX: Self = Self { value: i128::MAX };
23 pub const MIN: Self = Self { value: i128::MIN };
24 #[cfg(test)]
25 pub const STEP: Self = Self { value: 1 };
26
27 #[inline]
29 pub const fn new(i: i128, n: u32) -> Result<Self, TooLargeForDecimalError> {
30 let Some(shift) = DECIMAL_PART_DIGITS.checked_sub(n) else {
31 return Err(TooLargeForDecimalError);
32 };
33 let Some(value) = i.checked_mul(10_i128.pow(shift)) else {
34 return Err(TooLargeForDecimalError);
35 };
36 Ok(Self { value })
37 }
38
39 pub(crate) const fn new_from_i128_unchecked(value: i128) -> Self {
40 Self {
41 value: value * DECIMAL_PART_POW,
42 }
43 }
44
45 #[inline]
46 #[must_use]
47 pub fn from_be_bytes(bytes: [u8; 16]) -> Self {
48 Self {
49 value: i128::from_be_bytes(bytes),
50 }
51 }
52
53 #[inline]
54 #[must_use]
55 pub fn to_be_bytes(self) -> [u8; 16] {
56 self.value.to_be_bytes()
57 }
58
59 #[inline]
63 #[must_use]
64 pub fn checked_add(self, rhs: impl Into<Self>) -> Option<Self> {
65 Some(Self {
66 value: self.value.checked_add(rhs.into().value)?,
67 })
68 }
69
70 #[inline]
74 #[must_use]
75 pub fn checked_sub(self, rhs: impl Into<Self>) -> Option<Self> {
76 Some(Self {
77 value: self.value.checked_sub(rhs.into().value)?,
78 })
79 }
80
81 #[inline]
85 #[must_use]
86 pub fn checked_mul(self, rhs: impl Into<Self>) -> Option<Self> {
87 let mut left = self.value;
90 let mut shift_left = 0_u32;
91 if left != 0 {
92 while left % 10 == 0 {
93 left /= 10;
94 shift_left += 1;
95 }
96 }
97
98 let mut right = rhs.into().value;
99 let mut shift_right = 0_u32;
100 if right != 0 {
101 while right % 10 == 0 {
102 right /= 10;
103 shift_right += 1;
104 }
105 }
106
107 let shift = (shift_left + shift_right).checked_sub(DECIMAL_PART_DIGITS)?;
109 Some(Self {
110 value: left
111 .checked_mul(right)?
112 .checked_mul(10_i128.checked_pow(shift)?)?,
113 })
114 }
115
116 #[inline]
120 #[must_use]
121 pub fn checked_div(self, rhs: impl Into<Self>) -> Option<Self> {
122 let mut left = self.value;
126 let mut shift_left = 0_u32;
127 if left != 0 {
128 while let Some(r) = left.checked_mul(10) {
129 left = r;
130 shift_left += 1;
131 }
132 }
133 let mut right = rhs.into().value;
134 let mut shift_right = 0_u32;
135 if right != 0 {
136 while right % 10 == 0 {
137 right /= 10;
138 shift_right += 1;
139 }
140 }
141
142 let shift = (shift_left + shift_right).checked_sub(DECIMAL_PART_DIGITS)?;
144 Some(Self {
145 value: left
146 .checked_div(right)?
147 .checked_div(10_i128.checked_pow(shift)?)?,
148 })
149 }
150
151 #[inline]
155 #[must_use]
156 pub fn checked_rem(self, rhs: impl Into<Self>) -> Option<Self> {
157 Some(Self {
158 value: self.value.checked_rem(rhs.into().value)?,
159 })
160 }
161
162 #[inline]
166 #[must_use]
167 pub fn checked_rem_euclid(self, rhs: impl Into<Self>) -> Option<Self> {
168 Some(Self {
169 value: self.value.checked_rem_euclid(rhs.into().value)?,
170 })
171 }
172
173 #[inline]
177 #[must_use]
178 pub fn checked_neg(self) -> Option<Self> {
179 Some(Self {
180 value: self.value.checked_neg()?,
181 })
182 }
183
184 #[inline]
188 #[must_use]
189 pub fn checked_abs(self) -> Option<Self> {
190 Some(Self {
191 value: self.value.checked_abs()?,
192 })
193 }
194
195 #[inline]
199 #[must_use]
200 pub fn checked_round(self) -> Option<Self> {
201 let value = self.value / DECIMAL_PART_POW_MINUS_ONE;
202 Some(Self {
203 value: if value >= 0 {
204 value / 10 + i128::from(value % 10 >= 5)
205 } else {
206 value / 10 - i128::from(-value % 10 > 5)
207 }
208 .checked_mul(DECIMAL_PART_POW)?,
209 })
210 }
211
212 #[inline]
216 #[must_use]
217 pub fn checked_ceil(self) -> Option<Self> {
218 Some(Self {
219 value: if self.value > 0 && self.value % DECIMAL_PART_POW != 0 {
220 self.value / DECIMAL_PART_POW + 1
221 } else {
222 self.value / DECIMAL_PART_POW
223 }
224 .checked_mul(DECIMAL_PART_POW)?,
225 })
226 }
227
228 #[inline]
232 #[must_use]
233 pub fn checked_floor(self) -> Option<Self> {
234 Some(Self {
235 value: if self.value >= 0 || self.value % DECIMAL_PART_POW == 0 {
236 self.value / DECIMAL_PART_POW
237 } else {
238 self.value / DECIMAL_PART_POW - 1
239 }
240 .checked_mul(DECIMAL_PART_POW)?,
241 })
242 }
243
244 #[inline]
245 #[must_use]
246 pub const fn is_negative(self) -> bool {
247 self.value < 0
248 }
249
250 #[inline]
251 #[must_use]
252 pub const fn is_positive(self) -> bool {
253 self.value > 0
254 }
255
256 #[inline]
258 #[must_use]
259 pub fn is_identical_with(self, other: Self) -> bool {
260 self == other
261 }
262
263 #[inline]
264 #[must_use]
265 pub(super) const fn as_i128(self) -> i128 {
266 self.value / DECIMAL_PART_POW
267 }
268}
269
270impl From<bool> for Decimal {
271 #[inline]
272 fn from(value: bool) -> Self {
273 Self {
274 value: i128::from(value) * DECIMAL_PART_POW,
275 }
276 }
277}
278
279impl From<i8> for Decimal {
280 #[inline]
281 fn from(value: i8) -> Self {
282 Self {
283 value: i128::from(value) * DECIMAL_PART_POW,
284 }
285 }
286}
287
288impl From<i16> for Decimal {
289 #[inline]
290 fn from(value: i16) -> Self {
291 Self {
292 value: i128::from(value) * DECIMAL_PART_POW,
293 }
294 }
295}
296
297impl From<i32> for Decimal {
298 #[inline]
299 fn from(value: i32) -> Self {
300 Self {
301 value: i128::from(value) * DECIMAL_PART_POW,
302 }
303 }
304}
305
306impl From<i64> for Decimal {
307 #[inline]
308 fn from(value: i64) -> Self {
309 Self {
310 value: i128::from(value) * DECIMAL_PART_POW,
311 }
312 }
313}
314
315impl From<u8> for Decimal {
316 #[inline]
317 fn from(value: u8) -> Self {
318 Self {
319 value: i128::from(value) * DECIMAL_PART_POW,
320 }
321 }
322}
323
324impl From<u16> for Decimal {
325 #[inline]
326 fn from(value: u16) -> Self {
327 Self {
328 value: i128::from(value) * DECIMAL_PART_POW,
329 }
330 }
331}
332
333impl From<u32> for Decimal {
334 #[inline]
335 fn from(value: u32) -> Self {
336 Self {
337 value: i128::from(value) * DECIMAL_PART_POW,
338 }
339 }
340}
341
342impl From<u64> for Decimal {
343 #[inline]
344 fn from(value: u64) -> Self {
345 Self {
346 value: i128::from(value) * DECIMAL_PART_POW,
347 }
348 }
349}
350
351impl From<Integer> for Decimal {
352 #[inline]
353 fn from(value: Integer) -> Self {
354 i64::from(value).into()
355 }
356}
357
358impl TryFrom<i128> for Decimal {
359 type Error = TooLargeForDecimalError;
360
361 #[inline]
362 fn try_from(value: i128) -> Result<Self, Self::Error> {
363 Ok(Self {
364 value: value
365 .checked_mul(DECIMAL_PART_POW)
366 .ok_or(TooLargeForDecimalError)?,
367 })
368 }
369}
370
371impl TryFrom<u128> for Decimal {
372 type Error = TooLargeForDecimalError;
373
374 #[inline]
375 fn try_from(value: u128) -> Result<Self, Self::Error> {
376 Ok(Self {
377 value: i128::try_from(value)
378 .map_err(|_| TooLargeForDecimalError)?
379 .checked_mul(DECIMAL_PART_POW)
380 .ok_or(TooLargeForDecimalError)?,
381 })
382 }
383}
384
385impl From<Boolean> for Decimal {
386 #[inline]
387 fn from(value: Boolean) -> Self {
388 bool::from(value).into()
389 }
390}
391
392impl TryFrom<Float> for Decimal {
393 type Error = TooLargeForDecimalError;
394
395 #[inline]
396 fn try_from(value: Float) -> Result<Self, Self::Error> {
397 Double::from(value).try_into()
398 }
399}
400
401impl TryFrom<Double> for Decimal {
402 type Error = TooLargeForDecimalError;
403
404 #[inline]
405 #[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)]
406 fn try_from(value: Double) -> Result<Self, Self::Error> {
407 let shifted = f64::from(value) * (DECIMAL_PART_POW as f64);
408 if (i128::MIN as f64) <= shifted && shifted <= (i128::MAX as f64) {
409 Ok(Self {
410 value: shifted as i128,
411 })
412 } else {
413 Err(TooLargeForDecimalError)
414 }
415 }
416}
417
418impl From<Decimal> for Float {
419 #[inline]
420 #[allow(clippy::cast_precision_loss)]
421 fn from(value: Decimal) -> Self {
422 Double::from(value).into()
423 }
424}
425
426impl From<Decimal> for Double {
427 #[inline]
428 #[allow(clippy::cast_precision_loss)]
429 fn from(value: Decimal) -> Self {
430 let mut value = value.value;
431 let mut shift = DECIMAL_PART_POW;
432
433 if value != 0 {
435 while shift != 1 && value % 10 == 0 {
436 value /= 10;
437 shift /= 10;
438 }
439 }
440
441 ((value as f64) / (shift as f64)).into()
442 }
443}
444
445impl TryFrom<Decimal> for Integer {
446 type Error = TooLargeForIntegerError;
447
448 #[inline]
449 fn try_from(value: Decimal) -> Result<Self, Self::Error> {
450 Ok(i64::try_from(
451 value
452 .value
453 .checked_div(DECIMAL_PART_POW)
454 .ok_or(TooLargeForIntegerError)?,
455 )
456 .map_err(|_| TooLargeForIntegerError)?
457 .into())
458 }
459}
460
461impl FromStr for Decimal {
462 type Err = ParseDecimalError;
463
464 fn from_str(input: &str) -> Result<Self, Self::Err> {
466 let input = input.as_bytes();
468 if input.is_empty() {
469 return Err(PARSE_UNEXPECTED_END);
470 }
471
472 let (sign, mut input) = match input.first() {
473 Some(b'+') => (1_i128, &input[1..]),
474 Some(b'-') => (-1_i128, &input[1..]),
475 _ => (1, input),
476 };
477
478 let mut value = 0_i128;
479 let with_before_dot = input.first().is_some_and(u8::is_ascii_digit);
480 while let Some(c) = input.first() {
481 if c.is_ascii_digit() {
482 value = value
483 .checked_mul(10)
484 .ok_or(PARSE_OVERFLOW)?
485 .checked_add(sign * i128::from(*c - b'0'))
486 .ok_or(PARSE_OVERFLOW)?;
487 input = &input[1..];
488 } else {
489 break;
490 }
491 }
492
493 let mut exp = DECIMAL_PART_POW;
494 if let Some(c) = input.first() {
495 if *c != b'.' {
496 return Err(PARSE_UNEXPECTED_CHAR);
497 }
498 input = &input[1..];
499 if input.is_empty() && !with_before_dot {
500 return Err(PARSE_UNEXPECTED_END);
502 }
503 while input.last() == Some(&b'0') {
504 input = &input[..input.len() - 1];
506 }
507 while let Some(c) = input.first() {
508 if c.is_ascii_digit() {
509 exp /= 10;
510 value = value
511 .checked_mul(10)
512 .ok_or(PARSE_OVERFLOW)?
513 .checked_add(sign * i128::from(*c - b'0'))
514 .ok_or(PARSE_OVERFLOW)?;
515 input = &input[1..];
516 } else {
517 return Err(PARSE_UNEXPECTED_CHAR);
518 }
519 }
520 if exp == 0 {
521 return Err(PARSE_UNDERFLOW);
523 }
524 } else if !with_before_dot {
525 return Err(PARSE_UNEXPECTED_END);
527 }
528
529 Ok(Self {
530 value: value.checked_mul(exp).ok_or(PARSE_OVERFLOW)?,
531 })
532 }
533}
534
535impl fmt::Display for Decimal {
536 #[allow(clippy::cast_possible_truncation)]
538 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
539 if self.value == 0 {
540 return if let Some(width) = f.width() {
541 for _ in 0..width {
542 f.write_char('0')?;
543 }
544 Ok(())
545 } else {
546 f.write_char('0')
547 };
548 }
549
550 let mut value = self.value;
551 if self.value.is_negative() {
552 f.write_char('-')?;
553 }
554
555 let mut digits = [b'0'; 40];
556 let mut i = 0;
557 while value != 0 {
558 digits[i] = b'0' + ((value % 10).unsigned_abs() as u8);
559 value /= 10;
560 i += 1;
561 }
562
563 let last_non_zero = i - 1;
564 let first_non_zero = digits
565 .iter()
566 .copied()
567 .enumerate()
568 .find_map(|(i, v)| if v == b'0' { None } else { Some(i) })
569 .unwrap_or(40);
570
571 let decimal_part_digits = usize::try_from(DECIMAL_PART_DIGITS).map_err(|_| fmt::Error)?;
572 if last_non_zero >= decimal_part_digits {
573 let end = if let Some(mut width) = f.width() {
574 if self.value.is_negative() {
575 width -= 1;
576 }
577 if last_non_zero - decimal_part_digits + 1 < width {
578 decimal_part_digits + width
579 } else {
580 last_non_zero + 1
581 }
582 } else {
583 last_non_zero + 1
584 };
585 for c in digits[decimal_part_digits..end].iter().rev() {
586 f.write_char(char::from(*c))?;
587 }
588 } else {
589 f.write_char('0')?
590 }
591 if decimal_part_digits > first_non_zero {
592 f.write_char('.')?;
593 let start = if let Some(precision) = f.precision() {
594 if decimal_part_digits - first_non_zero > precision {
595 decimal_part_digits - precision
596 } else {
597 first_non_zero
598 }
599 } else {
600 first_non_zero
601 };
602 for c in digits[start..decimal_part_digits].iter().rev() {
603 f.write_char(char::from(*c))?;
604 }
605 }
606
607 Ok(())
608 }
609}
610
611#[derive(Debug, thiserror::Error)]
613#[error(transparent)]
614pub struct ParseDecimalError(#[from] DecimalParseErrorKind);
615
616#[derive(Debug, Clone, thiserror::Error)]
617enum DecimalParseErrorKind {
618 #[error("Value overflow")]
619 Overflow,
620 #[error("Value underflow")]
621 Underflow,
622 #[error("Unexpected character")]
623 UnexpectedChar,
624 #[error("Unexpected end of string")]
625 UnexpectedEnd,
626}
627
628const PARSE_OVERFLOW: ParseDecimalError = ParseDecimalError(DecimalParseErrorKind::Overflow);
629const PARSE_UNDERFLOW: ParseDecimalError = ParseDecimalError(DecimalParseErrorKind::Underflow);
630const PARSE_UNEXPECTED_CHAR: ParseDecimalError =
631 ParseDecimalError(DecimalParseErrorKind::UnexpectedChar);
632const PARSE_UNEXPECTED_END: ParseDecimalError =
633 ParseDecimalError(DecimalParseErrorKind::UnexpectedEnd);
634
635impl From<TooLargeForDecimalError> for ParseDecimalError {
636 fn from(_: TooLargeForDecimalError) -> Self {
637 Self(DecimalParseErrorKind::Overflow)
638 }
639}
640
641#[derive(Debug, Clone, Copy, thiserror::Error)]
645#[error("Value too large for xsd:decimal internal representation")]
646pub struct TooLargeForDecimalError;
647
648#[cfg(test)]
649#[allow(clippy::panic_in_result_fn)]
650mod tests {
651 use super::*;
652
653 #[test]
654 fn new() -> Result<(), ParseDecimalError> {
655 assert_eq!(Decimal::new(1, 0)?.to_string(), "1");
656 assert_eq!(Decimal::new(1, 1)?.to_string(), "0.1");
657 assert_eq!(Decimal::new(10, 0)?.to_string(), "10");
658 assert_eq!(Decimal::new(10, 1)?.to_string(), "1");
659 assert_eq!(Decimal::new(10, 2)?.to_string(), "0.1");
660 Ok(())
661 }
662
663 #[test]
664 fn from_str() -> Result<(), ParseDecimalError> {
665 Decimal::from_str("").unwrap_err();
666 Decimal::from_str("+").unwrap_err();
667 Decimal::from_str("-").unwrap_err();
668 Decimal::from_str(".").unwrap_err();
669 Decimal::from_str("+.").unwrap_err();
670 Decimal::from_str("-.").unwrap_err();
671 Decimal::from_str("a").unwrap_err();
672 Decimal::from_str(".a").unwrap_err();
673 assert_eq!(Decimal::from_str("210")?.to_string(), "210");
674 assert_eq!(Decimal::from_str("1000")?.to_string(), "1000");
675 assert_eq!(Decimal::from_str("-1.23")?.to_string(), "-1.23");
676 assert_eq!(
677 Decimal::from_str("12678967.543233")?.to_string(),
678 "12678967.543233"
679 );
680 assert_eq!(Decimal::from_str("+100000.00")?.to_string(), "100000");
681 assert_eq!(Decimal::from_str("0.1220")?.to_string(), "0.122");
682 assert_eq!(Decimal::from_str(".12200")?.to_string(), "0.122");
683 assert_eq!(Decimal::from_str("1.")?.to_string(), "1");
684 assert_eq!(Decimal::from_str("1.0")?.to_string(), "1");
685 assert_eq!(Decimal::from_str("01.0")?.to_string(), "1");
686 assert_eq!(Decimal::from_str("0")?.to_string(), "0");
687 assert_eq!(Decimal::from_str("-0")?.to_string(), "0");
688 assert_eq!(Decimal::from_str(&Decimal::MAX.to_string())?, Decimal::MAX);
689 assert_eq!(Decimal::from_str(&Decimal::MIN.to_string())?, Decimal::MIN);
690 Decimal::from_str("0.0000000000000000001").unwrap_err();
691 Decimal::from_str("1000000000000000000000").unwrap_err();
692 assert_eq!(
693 Decimal::from_str("0.100000000000000000000000000").unwrap(),
694 Decimal::from_str("0.1").unwrap()
695 );
696 Ok(())
697 }
698
699 #[test]
700 fn format() {
701 assert_eq!(format!("{}", Decimal::from(0)), "0");
702 assert_eq!(format!("{}", Decimal::from(1)), "1");
703 assert_eq!(format!("{}", Decimal::from(10)), "10");
704 assert_eq!(format!("{}", Decimal::from(100)), "100");
705 assert_eq!(format!("{}", Decimal::from(-1)), "-1");
706 assert_eq!(format!("{}", Decimal::from(-10)), "-10");
707
708 assert_eq!(format!("{:02}", Decimal::from(0)), "00");
709 assert_eq!(format!("{:02}", Decimal::from(1)), "01");
710 assert_eq!(format!("{:02}", Decimal::from(10)), "10");
711 assert_eq!(format!("{:02}", Decimal::from(100)), "100");
712 assert_eq!(format!("{:02}", Decimal::from(-1)), "-1");
713 assert_eq!(format!("{:02}", Decimal::from(-10)), "-10");
714 }
715
716 #[test]
717 fn add() {
718 assert!(Decimal::MIN.checked_add(Decimal::STEP).is_some());
719 assert!(Decimal::MAX.checked_add(Decimal::STEP).is_none());
720 assert_eq!(
721 Decimal::MAX.checked_add(Decimal::MIN),
722 Decimal::STEP.checked_neg()
723 );
724 }
725
726 #[test]
727 fn sub() {
728 assert!(Decimal::MIN.checked_sub(Decimal::STEP).is_none());
729 assert!(Decimal::MAX.checked_sub(Decimal::STEP).is_some());
730 }
731
732 #[test]
733 fn mul() -> Result<(), ParseDecimalError> {
734 assert_eq!(Decimal::from(1).checked_mul(-1), Some(Decimal::from(-1)));
735 assert_eq!(
736 Decimal::from(1000).checked_mul(1000),
737 Some(Decimal::from(1_000_000))
738 );
739 assert_eq!(
740 Decimal::from_str("0.1")?.checked_mul(Decimal::from_str("0.01")?),
741 Some(Decimal::from_str("0.001")?)
742 );
743 assert_eq!(Decimal::from(0).checked_mul(1), Some(Decimal::from(0)));
744 assert_eq!(Decimal::from(1).checked_mul(0), Some(Decimal::from(0)));
745 assert_eq!(Decimal::MAX.checked_mul(1), Some(Decimal::MAX));
746 assert_eq!(Decimal::MIN.checked_mul(1), Some(Decimal::MIN));
747 assert_eq!(
748 Decimal::from(1).checked_mul(Decimal::MAX),
749 Some(Decimal::MAX)
750 );
751 assert_eq!(
752 Decimal::from(1).checked_mul(Decimal::MIN),
753 Some(Decimal::MIN)
754 );
755 assert_eq!(
756 Decimal::MAX.checked_mul(-1),
757 Some(Decimal::MIN.checked_add(Decimal::STEP).unwrap())
758 );
759 assert_eq!(Decimal::MIN.checked_mul(-1), None);
760 assert_eq!(
761 Decimal::MIN
762 .checked_add(Decimal::STEP)
763 .unwrap()
764 .checked_mul(-1),
765 Some(Decimal::MAX)
766 );
767 Ok(())
768 }
769
770 #[test]
771 fn div() -> Result<(), ParseDecimalError> {
772 assert_eq!(Decimal::from(1).checked_div(1), Some(Decimal::from(1)));
773 assert_eq!(Decimal::from(100).checked_div(10), Some(Decimal::from(10)));
774 assert_eq!(
775 Decimal::from(10).checked_div(100),
776 Some(Decimal::from_str("0.1")?)
777 );
778 assert_eq!(Decimal::from(1).checked_div(0), None);
779 assert_eq!(Decimal::from(0).checked_div(1), Some(Decimal::from(0)));
780 assert_eq!(Decimal::MAX.checked_div(1), Some(Decimal::MAX));
781 assert_eq!(Decimal::MIN.checked_div(1), Some(Decimal::MIN));
782 assert_eq!(
783 Decimal::MAX.checked_div(-1),
784 Some(Decimal::MIN.checked_add(Decimal::STEP).unwrap())
785 );
786 assert_eq!(Decimal::MIN.checked_div(-1), None);
787 assert_eq!(
788 Decimal::MIN
789 .checked_add(Decimal::STEP)
790 .unwrap()
791 .checked_div(-1),
792 Some(Decimal::MAX)
793 );
794 Ok(())
795 }
796
797 #[test]
798 fn rem() -> Result<(), ParseDecimalError> {
799 assert_eq!(Decimal::from(10).checked_rem(3), Some(Decimal::from(1)));
800 assert_eq!(Decimal::from(6).checked_rem(-2), Some(Decimal::from(0)));
801 assert_eq!(
802 Decimal::from_str("4.5")?.checked_rem(Decimal::from_str("1.2")?),
803 Some(Decimal::from_str("0.9")?)
804 );
805 assert_eq!(Decimal::from(1).checked_rem(0), None);
806 assert_eq!(
807 Decimal::MAX.checked_rem(1),
808 Some(Decimal::from_str("0.687303715884105727")?)
809 );
810 assert_eq!(
811 Decimal::MIN.checked_rem(1),
812 Some(Decimal::from_str("-0.687303715884105728")?)
813 );
814 assert_eq!(
815 Decimal::MAX.checked_rem(Decimal::STEP),
816 Some(Decimal::default())
817 );
818 assert_eq!(
819 Decimal::MIN.checked_rem(Decimal::STEP),
820 Some(Decimal::default())
821 );
822 assert_eq!(
823 Decimal::MAX.checked_rem(Decimal::MAX),
824 Some(Decimal::default())
825 );
826 assert_eq!(
827 Decimal::MIN.checked_rem(Decimal::MIN),
828 Some(Decimal::default())
829 );
830 Ok(())
831 }
832
833 #[test]
834 fn round() -> Result<(), ParseDecimalError> {
835 assert_eq!(Decimal::from(10).checked_round(), Some(Decimal::from(10)));
836 assert_eq!(Decimal::from(-10).checked_round(), Some(Decimal::from(-10)));
837 assert_eq!(
838 Decimal::from(i64::MIN).checked_round(),
839 Some(Decimal::from(i64::MIN))
840 );
841 assert_eq!(
842 Decimal::from(i64::MAX).checked_round(),
843 Some(Decimal::from(i64::MAX))
844 );
845 assert_eq!(
846 Decimal::from_str("2.5")?.checked_round(),
847 Some(Decimal::from(3))
848 );
849 assert_eq!(
850 Decimal::from_str("2.4999")?.checked_round(),
851 Some(Decimal::from(2))
852 );
853 assert_eq!(
854 Decimal::from_str("-2.5")?.checked_round(),
855 Some(Decimal::from(-2))
856 );
857 assert_eq!(Decimal::MAX.checked_round(), None);
858 assert_eq!(
859 Decimal::MAX
860 .checked_sub(Decimal::from_str("0.5")?)
861 .unwrap()
862 .checked_round(),
863 Some(Decimal::from_str("170141183460469231731")?)
864 );
865 assert_eq!(Decimal::MIN.checked_round(), None);
866 assert_eq!(
867 Decimal::MIN
868 .checked_add(Decimal::from_str("0.5")?)
869 .unwrap()
870 .checked_round(),
871 Some(Decimal::from_str("-170141183460469231731")?)
872 );
873 Ok(())
874 }
875
876 #[test]
877 fn ceil() -> Result<(), ParseDecimalError> {
878 assert_eq!(Decimal::from(10).checked_ceil(), Some(Decimal::from(10)));
879 assert_eq!(Decimal::from(-10).checked_ceil(), Some(Decimal::from(-10)));
880 assert_eq!(
881 Decimal::from_str("10.5")?.checked_ceil(),
882 Some(Decimal::from(11))
883 );
884 assert_eq!(
885 Decimal::from_str("-10.5")?.checked_ceil(),
886 Some(Decimal::from(-10))
887 );
888 assert_eq!(
889 Decimal::from(i64::MIN).checked_ceil(),
890 Some(Decimal::from(i64::MIN))
891 );
892 assert_eq!(
893 Decimal::from(i64::MAX).checked_ceil(),
894 Some(Decimal::from(i64::MAX))
895 );
896 assert_eq!(Decimal::MAX.checked_ceil(), None);
897 assert_eq!(
898 Decimal::MAX
899 .checked_sub(Decimal::from(1))
900 .unwrap()
901 .checked_ceil(),
902 Some(Decimal::from_str("170141183460469231731")?)
903 );
904 assert_eq!(
905 Decimal::MIN.checked_ceil(),
906 Some(Decimal::from_str("-170141183460469231731")?)
907 );
908 Ok(())
909 }
910
911 #[test]
912 fn floor() -> Result<(), ParseDecimalError> {
913 assert_eq!(Decimal::from(10).checked_floor(), Some(Decimal::from(10)));
914 assert_eq!(Decimal::from(-10).checked_floor(), Some(Decimal::from(-10)));
915 assert_eq!(
916 Decimal::from_str("10.5")?.checked_floor(),
917 Some(Decimal::from(10))
918 );
919 assert_eq!(
920 Decimal::from_str("-10.5")?.checked_floor(),
921 Some(Decimal::from(-11))
922 );
923 assert_eq!(
924 Decimal::from(i64::MIN).checked_floor(),
925 Some(Decimal::from(i64::MIN))
926 );
927 assert_eq!(
928 Decimal::from(i64::MAX).checked_floor(),
929 Some(Decimal::from(i64::MAX))
930 );
931 assert_eq!(
932 Decimal::MAX.checked_floor(),
933 Some(Decimal::from_str("170141183460469231731")?)
934 );
935 assert_eq!(Decimal::MIN.checked_floor(), None);
936 assert_eq!(
937 Decimal::MIN
938 .checked_add(Decimal::from_str("1")?)
939 .unwrap()
940 .checked_floor(),
941 Some(Decimal::from_str("-170141183460469231731")?)
942 );
943 Ok(())
944 }
945
946 #[test]
947 fn to_be_bytes() -> Result<(), ParseDecimalError> {
948 assert_eq!(
949 Decimal::from_be_bytes(Decimal::MIN.to_be_bytes()),
950 Decimal::MIN
951 );
952 assert_eq!(
953 Decimal::from_be_bytes(Decimal::MAX.to_be_bytes()),
954 Decimal::MAX
955 );
956 assert_eq!(
957 Decimal::from_be_bytes(Decimal::from(i64::MIN).to_be_bytes()),
958 Decimal::from(i64::MIN)
959 );
960 assert_eq!(
961 Decimal::from_be_bytes(Decimal::from(i64::MAX).to_be_bytes()),
962 Decimal::from(i64::MAX)
963 );
964 assert_eq!(
965 Decimal::from_be_bytes(Decimal::from(0).to_be_bytes()),
966 Decimal::from(0)
967 );
968 assert_eq!(
969 Decimal::from_be_bytes(Decimal::from(0).to_be_bytes()),
970 Decimal::from(0)
971 );
972 assert_eq!(
973 Decimal::from_be_bytes(Decimal::from_str("0.01")?.to_be_bytes()),
974 Decimal::from_str("0.01")?
975 );
976 Ok(())
977 }
978
979 #[test]
980 fn from_bool() {
981 assert_eq!(Decimal::from(false), Decimal::from(0_u8));
982 assert_eq!(Decimal::from(true), Decimal::from(1_u8));
983 }
984
985 #[test]
986 fn from_float() -> Result<(), ParseDecimalError> {
987 assert_eq!(
988 Decimal::try_from(Float::from(0.)).ok(),
989 Some(Decimal::from(0))
990 );
991 assert_eq!(
992 Decimal::try_from(Float::from(-0.)).ok(),
993 Some(Decimal::from(0))
994 );
995 assert_eq!(
996 Decimal::try_from(Float::from(-123.5)).ok(),
997 Some(Decimal::from_str("-123.5")?)
998 );
999 Decimal::try_from(Float::from(f32::NAN)).unwrap_err();
1000 Decimal::try_from(Float::from(f32::INFINITY)).unwrap_err();
1001 Decimal::try_from(Float::from(f32::NEG_INFINITY)).unwrap_err();
1002 Decimal::try_from(Float::from(f32::MIN)).unwrap_err();
1003 Decimal::try_from(Float::from(f32::MAX)).unwrap_err();
1004 assert!(
1005 Decimal::try_from(Float::from(1_672_507_300_000.))
1006 .unwrap()
1007 .checked_sub(Decimal::from(1_672_507_293_696_i64))
1008 .unwrap()
1009 .checked_abs()
1010 .unwrap()
1011 < Decimal::from(1)
1012 );
1013 Ok(())
1014 }
1015
1016 #[test]
1017 fn from_double() -> Result<(), ParseDecimalError> {
1018 assert_eq!(
1019 Decimal::try_from(Double::from(0.)).ok(),
1020 Some(Decimal::from(0))
1021 );
1022 assert_eq!(
1023 Decimal::try_from(Double::from(-0.)).ok(),
1024 Some(Decimal::from(0))
1025 );
1026 assert_eq!(
1027 Decimal::try_from(Double::from(-123.1)).ok(),
1028 Some(Decimal::from_str("-123.1")?)
1029 );
1030 assert!(
1031 Decimal::try_from(Double::from(1_672_507_302_466.))
1032 .unwrap()
1033 .checked_sub(Decimal::from(1_672_507_302_466_i64))
1034 .unwrap()
1035 .checked_abs()
1036 .unwrap()
1037 < Decimal::from(1)
1038 );
1039 Decimal::try_from(Double::from(f64::NAN)).unwrap_err();
1040 Decimal::try_from(Double::from(f64::INFINITY)).unwrap_err();
1041 Decimal::try_from(Double::from(f64::NEG_INFINITY)).unwrap_err();
1042 Decimal::try_from(Double::from(f64::MIN)).unwrap_err();
1043 Decimal::try_from(Double::from(f64::MAX)).unwrap_err();
1044 Ok(())
1045 }
1046
1047 #[test]
1048 fn to_float() -> Result<(), ParseDecimalError> {
1049 assert_eq!(Float::from(Decimal::from(0)), Float::from(0.));
1050 assert_eq!(Float::from(Decimal::from(1)), Float::from(1.));
1051 assert_eq!(Float::from(Decimal::from(10)), Float::from(10.));
1052 assert_eq!(Float::from(Decimal::from_str("0.1")?), Float::from(0.1));
1053 assert!((Float::from(Decimal::MAX) - Float::from(1.701_412e20)).abs() < Float::from(1.));
1054 assert!((Float::from(Decimal::MIN) - Float::from(-1.701_412e20)).abs() < Float::from(1.));
1055 Ok(())
1056 }
1057
1058 #[test]
1059 fn to_double() -> Result<(), ParseDecimalError> {
1060 assert_eq!(Double::from(Decimal::from(0)), Double::from(0.));
1061 assert_eq!(Double::from(Decimal::from(1)), Double::from(1.));
1062 assert_eq!(Double::from(Decimal::from(10)), Double::from(10.));
1063 assert!(
1064 Double::from(Decimal::from_str("0.1")?) - Double::from(0.1)
1065 < Double::from(f64::from(f32::EPSILON))
1066 );
1067 assert!(
1068 (Double::from(Decimal::MAX) - Double::from(1.701_411_834_604_692_4e20)).abs()
1069 < Double::from(1.)
1070 );
1071 assert!(
1072 (Double::from(Decimal::MIN) - Double::from(-1.701_411_834_604_692_4e20)).abs()
1073 < Double::from(1.)
1074 );
1075 Ok(())
1076 }
1077
1078 #[test]
1079 fn minimally_conformant() -> Result<(), ParseDecimalError> {
1080 assert_eq!(
1083 Decimal::from_str("1234567890123456")?.to_string(),
1084 "1234567890123456"
1085 );
1086 assert_eq!(
1087 Decimal::from_str("-1234567890123456")?.to_string(),
1088 "-1234567890123456"
1089 );
1090 assert_eq!(
1091 Decimal::from_str("0.1234567890123456")?.to_string(),
1092 "0.1234567890123456"
1093 );
1094 assert_eq!(
1095 Decimal::from_str("-0.1234567890123456")?.to_string(),
1096 "-0.1234567890123456"
1097 );
1098 Ok(())
1099 }
1100}