devela/num/unit/
traits.rs

1// devela::num::unit::traits
2//
3//! Unit prefixes traits.
4//
5// TOC
6// - trait Unit
7// - impl Unit for UnitBi, UnitSi.
8
9use super::{UnitBi, UnitSi};
10#[cfg(feature = "alloc")]
11use crate::data::Vec;
12
13/// Common trait for unit prefixes.
14///
15/// - <https://en.wikipedia.org/wiki/Unit_of_measurement>
16pub trait Unit: Sized {
17    /// Returns the symbol of the prefix.
18    #[must_use]
19    fn symbol(&self) -> &str;
20    /// Returns the ASCII symbol of the prefix.
21    #[must_use]
22    fn symbol_ascii(&self) -> &str;
23    /// Returns the name of the prefix.
24    #[must_use]
25    fn name(&self) -> &str;
26
27    /// Returns the multiplication factor for the prefix as an f64.
28    #[must_use]
29    fn factor(&self) -> f64;
30    /// Returns the multiplication factor for the prefix as an i64.
31    #[must_use]
32    fn factor_i64(&self) -> i64;
33    /// Returns the multiplication factor for the prefix as an i128.
34    #[must_use]
35    fn factor_i128(&self) -> i128;
36
37    /// Returns an iterator in ascending order of magnitude.
38    fn asc_iter() -> impl Iterator<Item = Self>;
39    /// Returns an iterator in descending order of magnitude.
40    fn desc_iter() -> impl Iterator<Item = Self>;
41
42    /// The base value for unit prefixes.
43    const BASE: Option<i32> = None;
44    /// Returns the exponent corresponding to the unit prefix.
45    #[must_use]
46    fn exp(&self) -> Option<i32> {
47        None
48    }
49
50    /// Converts a value from one unit prefix variant to another,
51    /// returning the converted value.
52    #[must_use]
53    fn convert(value: f64, from: Self, to: Self) -> f64;
54    /// Converts a value from one prefix to another,
55    /// returning the converted value and the remainder.
56    #[must_use]
57    fn convert_i64(value: i64, from: Self, to: Self) -> (i64, i64);
58    /// Converts a value from one prefix to another,
59    /// returning the converted value and the remainder.
60    #[must_use]
61    fn convert_i128(value: i128, from: Self, to: Self) -> (i128, i128);
62
63    /// Reduces the given `value` to the most appropriate prefix as a f64,
64    /// returning a tuple of the reduced size and the prefix.
65    ///
66    /// The input `value` is assumed to be non-negative, and in base units,
67    /// meaning it has no prefix applied.
68    ///
69    /// This method simplifies large numerical values by scaling them down
70    /// to the largest appropriate prefix (e.g., Kibi, Mebi, Gibi, etc.).
71    #[must_use]
72    #[cfg(any(feature = "std", feature = "_float_f64"))]
73    fn reduce(value: f64) -> (f64, Self);
74    /// Reduces the given value to the most appropriate prefix as a i64,
75    /// returning a tuple of the reduced size, the prefix, and the remainder.
76    ///
77    /// The input `value` is assumed to be non-negative, and in base units,
78    /// meaning it has no prefix applied.
79    ///
80    /// This method simplifies large numerical values by scaling them down
81    /// to the largest appropriate prefix (e.g., Kibi, Mebi, Gibi, etc.).
82    #[must_use]
83    fn reduce_i64(value: i64) -> (i64, Self, i64);
84    /// Reduces the given value to the most appropriate prefix as a i128,
85    /// returning a tuple of the reduced size, the prefix, and the remainder.
86    ///
87    /// The input `value` is assumed to be non-negative, and in base units,
88    /// meaning it has no prefix applied.
89    ///
90    /// This method simplifies large numerical values by scaling them down
91    /// to the largest appropriate prefix (e.g., Kibi, Mebi, Gibi, etc.).
92    #[must_use]
93    fn reduce_i128(value: i128) -> (i128, Self, i128);
94
95    /// Reduces the given value to a chain of appropriate prefixes as f64,
96    /// stopping when the remainder is less than the given threshold.
97    #[must_use]
98    #[cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64")))]
99    fn reduce_chain(value: f64, threshold: f64) -> Vec<(f64, Self)>;
100    /// Reduces the given value to a chain of appropriate prefixes as i64,
101    /// stopping when the remainder is less than the given threshold.
102    #[must_use]
103    #[cfg(feature = "alloc")]
104    fn reduce_chain_i64(value: i64, threshold: i64) -> Vec<(i64, Self)>;
105    /// Reduces the given value to a chain of appropriate prefixes as i128,
106    /// stopping when the remainder is less than the given threshold.
107    #[must_use]
108    #[cfg(feature = "alloc")]
109    fn reduce_chain_i128(value: i128, threshold: i128) -> Vec<(i128, Self)>;
110}
111
112// -----------------------------------------------------------------------------
113
114macro_rules! impl_unit {
115    ($($t:ty),+) => { $( impl_unit![@$t]; )+ };
116    (@$t:ty) => {
117        impl Unit for $t {
118            fn symbol(&self) -> &str { self.symbol() }
119            fn symbol_ascii(&self) -> &str { self.symbol_ascii() }
120            fn name(&self) -> &str { self.name() }
121
122            fn factor(&self) -> f64 { self.factor() }
123            fn factor_i64(&self) -> i64 { self.factor_i64() }
124            fn factor_i128(&self) -> i128 { self.factor_i128() }
125
126            fn asc_iter() -> impl Iterator<Item = Self> { Self::asc_iter() }
127            fn desc_iter() -> impl Iterator<Item = Self> { Self::desc_iter() }
128
129            const BASE: Option<i32> = Some(Self::BASE);
130            fn exp(&self) -> Option<i32> { Some(self.exp()) }
131
132            fn convert(value: f64, from: Self, to: Self) -> f64 {
133                Self::convert(value, from, to)
134            }
135            fn convert_i64(value: i64, from: Self, to: Self) -> (i64, i64) {
136                Self::convert_i64(value, from, to)
137            }
138            fn convert_i128(value: i128, from: Self, to: Self) -> (i128, i128) {
139                Self::convert_i128(value, from, to)
140            }
141
142            #[cfg(any(feature = "std", feature = "_float_f64"))]
143            fn reduce(value: f64) -> (f64, Self) { Self::reduce(value) }
144            fn reduce_i64(value: i64) -> (i64, Self, i64) { Self::reduce_i64(value) }
145            fn reduce_i128(value: i128) -> (i128, Self, i128){ Self::reduce_i128(value) }
146
147            #[cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64")))]
148            fn reduce_chain(value: f64, threshold: f64) -> Vec<(f64, Self)> {
149                Self::reduce_chain(value, threshold)
150            }
151            #[cfg(feature = "alloc")]
152            fn reduce_chain_i64(value: i64, threshold: i64) -> Vec<(i64, Self)> {
153                Self::reduce_chain_i64(value, threshold)
154            }
155            #[cfg(feature = "alloc")]
156            fn reduce_chain_i128(value: i128, threshold: i128) -> Vec<(i128, Self)> {
157                Self::reduce_chain_i128(value, threshold)
158            }
159        }
160    };
161}
162impl_unit![UnitBi, UnitSi];