1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

//! `fixed_decimal` is a utility crate of the [`ICU4X`] project.
//!
//! This crate provides [`SignedFixedDecimal`] and [`UnsignedFixedDecimal`], essential APIs for representing numbers in a human-readable format.
//! These types are particularly useful for formatting and plural rule selection, and are optimized for operations on individual digits.
//!
//! # Examples
//!
//! ```
//! use fixed_decimal::SignedFixedDecimal;
//!
//! let mut dec = SignedFixedDecimal::from(250);
//! dec.multiply_pow10(-2);
//! assert_eq!("2.50", format!("{}", dec));
//!
//! #[derive(Debug, PartialEq)]
//! struct MagnitudeAndDigit(i16, u8);
//!
//! let digits: Vec<MagnitudeAndDigit> = dec
//!     .magnitude_range()
//!     .map(|m| MagnitudeAndDigit(m, dec.digit_at(m)))
//!     .collect();
//!
//! assert_eq!(
//!     vec![
//!         MagnitudeAndDigit(-2, 0),
//!         MagnitudeAndDigit(-1, 5),
//!         MagnitudeAndDigit(0, 2)
//!     ],
//!     digits
//! );
//! ```
//!
//! [`ICU4X`]: ../icu/index.html

// https://github.com/unicode-org/icu4x/blob/main/documents/process/boilerplate.md#library-annotations
#![cfg_attr(not(any(test, feature = "std")), no_std)]
#![cfg_attr(
    not(test),
    deny(
        clippy::indexing_slicing,
        clippy::unwrap_used,
        clippy::expect_used,
        clippy::panic,
        clippy::exhaustive_structs,
        clippy::exhaustive_enums,
        missing_debug_implementations,
    )
)]

mod compact;
mod decimal;
mod integer;
mod ops;
mod rounding;
mod scientific;
mod signed_decimal;
mod uint_iterator;
mod variations;

#[cfg(feature = "ryu")]
pub use rounding::FloatPrecision;

// use variations::Signed;
// use variations::WithInfinity;
// use variations::WithNaN;
#[cfg(feature = "ryu")]
#[doc(no_inline)]
pub use FloatPrecision as DoublePrecision;

pub use compact::CompactDecimal;
pub use decimal::UnsignedFixedDecimal;
use displaydoc::Display;
pub use integer::FixedInteger;
pub use rounding::RoundingIncrement;
pub use rounding::SignedRoundingMode;
pub use rounding::UnsignedRoundingMode;
pub use scientific::ScientificDecimal;
pub use signed_decimal::SignedFixedDecimal;
pub use variations::Sign;
pub use variations::SignDisplay;
pub use variations::Signed;

pub(crate) use rounding::IncrementLike;
pub(crate) use rounding::NoIncrement;

/// The magnitude or number of digits exceeds the limit of the [`UnsignedFixedDecimal`] or [`SignedFixedDecimal`].
///
/// The highest
/// magnitude of the most significant digit is [`i16::MAX`], and the lowest magnitude of the
/// least significant digit is [`i16::MIN`].
///
/// This error is also returned when constructing a [`FixedInteger`] from a [`SignedFixedDecimal`] with a
/// fractional part.
///
/// # Examples
///
/// ```
/// use fixed_decimal::SignedFixedDecimal;
/// use fixed_decimal::LimitError;
///
/// let mut dec1 = SignedFixedDecimal::from(123);
/// dec1.multiply_pow10(i16::MAX);
/// assert!(dec1.is_zero());
/// ```
#[derive(Display, Debug, Copy, Clone, PartialEq)]
#[allow(clippy::exhaustive_structs)]
#[displaydoc("Magnitude or number of digits exceeded")]
pub struct LimitError;

/// An error involving FixedDecimal operations or conversion.
#[derive(Display, Debug, Copy, Clone, PartialEq)]
#[non_exhaustive]
pub enum ParseError {
    /// See [`LimitError`].
    #[displaydoc("Magnitude or number of digits exceeded")]
    Limit,
    /// The input of a string that is supposed to be converted to FixedDecimal is not accepted.
    ///
    /// Any string with non-digit characters (except for one '.' and one '-' at the beginning of the string) is not accepted.
    /// Also, empty string ("") and its negation ("-") are not accepted.
    /// Strings of form "12_345_678" are not accepted, the accepted format is "12345678".
    /// Also '.' shouldn't be first or the last characters, i. e. .123 and 123. are not accepted, and instead 0.123 and
    /// 123 (or 123.0) must be used.
    #[displaydoc("Failed to parse the input string")]
    Syntax,
}

#[cfg(feature = "std")]
impl std::error::Error for ParseError {}

// TODO(#5065): implement these while `WithCompactExponent` and `WithScientificExponent` are implemented.
// pub type FixedDecimalOrInfinity = WithInfinity<UnsignedFixedDecimal>;
// pub type SignedFixedDecimalOrInfinity = Signed<FixedDecimalOrInfinity>;
// pub type SignedFixedDecimalOrInfinityOrNan = WithNaN<SignedFixedDecimalOrInfinity>;