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