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];