Skip to main content

fixed_decimal/
lib.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
5// https://github.com/unicode-org/icu4x/blob/main/documents/process/boilerplate.md#library-annotations
6#![cfg_attr(not(any(test, doc)), no_std)]
7#![cfg_attr(
8    not(test),
9    deny(
10        clippy::indexing_slicing,
11        clippy::unwrap_used,
12        clippy::expect_used,
13        clippy::panic,
14    )
15)]
16#![warn(missing_docs)]
17
18//! `fixed_decimal` is a utility crate of the [`ICU4X`] project.
19//!
20//! This crate provides [`Decimal`] and [`UnsignedDecimal`], essential APIs for representing numbers in a human-readable format.
21//! These types are particularly useful for formatting and plural rule selection, and are optimized for operations on individual digits.
22//!
23//! # Examples
24//!
25//! ```
26//! use fixed_decimal::Decimal;
27//!
28//! let mut dec = Decimal::from(250);
29//! dec.multiply_pow10(-2);
30//! assert_eq!("2.50", format!("{}", dec));
31//!
32//! #[derive(Debug, PartialEq)]
33//! struct MagnitudeAndDigit(i16, u8);
34//!
35//! let digits: Vec<MagnitudeAndDigit> = dec
36//!     .magnitude_range()
37//!     .map(|m| MagnitudeAndDigit(m, dec.digit_at(m)))
38//!     .collect();
39//!
40//! assert_eq!(
41//!     vec![
42//!         MagnitudeAndDigit(-2, 0),
43//!         MagnitudeAndDigit(-1, 5),
44//!         MagnitudeAndDigit(0, 2)
45//!     ],
46//!     digits
47//! );
48//! ```
49//!
50//! [`ICU4X`]: ../icu/index.html
51
52mod compact;
53mod decimal;
54mod integer;
55mod ops;
56#[allow(missing_docs)] // todo
57mod rounding;
58mod scientific;
59mod signed_decimal;
60mod uint_iterator;
61mod variations;
62
63#[cfg(feature = "ryu")]
64pub use rounding::FloatPrecision;
65
66// use variations::Signed;
67// use variations::WithInfinity;
68// use variations::WithNaN;
69#[cfg(feature = "ryu")]
70#[doc(no_inline)]
71pub use FloatPrecision as DoublePrecision;
72
73pub use compact::CompactDecimal;
74pub use decimal::UnsignedDecimal;
75use displaydoc::Display;
76pub use integer::FixedInteger;
77pub use rounding::RoundingIncrement;
78pub use rounding::SignedRoundingMode;
79pub use rounding::UnsignedRoundingMode;
80pub use scientific::ScientificDecimal;
81pub use signed_decimal::Decimal;
82pub use variations::Sign;
83pub use variations::SignDisplay;
84pub use variations::Signed;
85
86pub(crate) use rounding::IncrementLike;
87pub(crate) use rounding::NoIncrement;
88
89/// The magnitude or number of digits exceeds the limit of the [`UnsignedDecimal`] or [`Decimal`].
90///
91/// The highest
92/// magnitude of the most significant digit is [`i16::MAX`], and the lowest magnitude of the
93/// least significant digit is [`i16::MIN`].
94///
95/// This error is also returned when constructing a [`FixedInteger`] from a [`Decimal`] with a
96/// fractional part.
97///
98/// # Examples
99///
100/// ```
101/// use fixed_decimal::Decimal;
102/// use fixed_decimal::LimitError;
103///
104/// let mut dec1 = Decimal::from(123);
105/// dec1.multiply_pow10(i16::MAX);
106/// assert!(dec1.is_zero());
107/// ```
108#[derive(Display, Debug, Copy, Clone, PartialEq)]
109#[allow(clippy::exhaustive_structs)]
110#[displaydoc("Magnitude or number of digits exceeded")]
111pub struct LimitError;
112
113/// An error involving [`Decimal`] operations or conversion.
114#[derive(Display, Debug, Copy, Clone, PartialEq)]
115#[non_exhaustive]
116pub enum ParseError {
117    /// See [`LimitError`].
118    #[displaydoc("Magnitude or number of digits exceeded")]
119    Limit,
120    /// The input of a string that is supposed to be converted to [`Decimal`] is not accepted.
121    ///
122    /// Any string with non-digit characters (except for one '.' and one '-' at the beginning of the string) is not accepted.
123    /// Also, empty string ("") and its negation ("-") are not accepted.
124    /// Strings of form `12_345_678` are not accepted, the accepted format is `12345678`.
125    /// Also `.` shouldn't be first or the last characters, i. e. `.123` and `123.` are not accepted, and instead `0.123` and
126    /// `123` (or `123.0`) must be used.
127    #[displaydoc("Failed to parse the input string")]
128    Syntax,
129}
130
131impl core::error::Error for ParseError {}
132
133// TODO(#5065): implement these while `WithCompactExponent` and `WithScientificExponent` are implemented.
134// pub type FixedDecimalOrInfinity = WithInfinity<UnsignedDecimal>;
135// pub type DecimalOrInfinity = Signed<FixedDecimalOrInfinity>;
136// pub type DecimalOrInfinityOrNan = WithNaN<DecimalOrInfinity>;