1use ::qty_macros::EnumIter;
11
12#[derive(Copy, Clone, Debug, Eq, PartialEq, EnumIter)]
17pub enum SIPrefix {
18 QUECTO = -30,
20 RONTO = -27,
22 YOCTO = -24,
24 ZEPTO = -21,
26 ATTO = -18,
28 FEMTO = -15,
30 PICO = -12,
32 NANO = -9,
34 MICRO = -6,
36 MILLI = -3,
38 CENTI = -2,
40 DECI = -1,
42 NONE = 0,
44 DECA = 1,
46 HECTO = 2,
48 KILO = 3,
50 MEGA = 6,
52 GIGA = 9,
54 TERA = 12,
56 PETA = 15,
58 EXA = 18,
60 ZETTA = 21,
62 YOTTA = 24,
64 RONNA = 27,
66 QUETTA = 30,
68}
69
70impl SIPrefix {
71 #[must_use]
73 pub const fn name(&self) -> &'static str {
74 match self {
75 Self::QUECTO => "Quecto",
76 Self::RONTO => "Ronto",
77 Self::YOCTO => "Yocto",
78 Self::ZEPTO => "Zepto",
79 Self::ATTO => "Atto",
80 Self::FEMTO => "Femto",
81 Self::PICO => "Pico",
82 Self::NANO => "Nano",
83 Self::MICRO => "Micro",
84 Self::MILLI => "Milli",
85 Self::CENTI => "Centi",
86 Self::DECI => "Deci",
87 Self::NONE => "",
88 Self::DECA => "Deca",
89 Self::HECTO => "Hecto",
90 Self::KILO => "Kilo",
91 Self::MEGA => "Mega",
92 Self::GIGA => "Giga",
93 Self::TERA => "Tera",
94 Self::PETA => "Peta",
95 Self::EXA => "Exa",
96 Self::ZETTA => "Zetta",
97 Self::YOTTA => "Yotta",
98 Self::RONNA => "Ronna",
99 Self::QUETTA => "Quetta",
100 }
101 }
102
103 #[must_use]
105 pub const fn abbr(&self) -> &'static str {
106 match self {
107 Self::QUECTO => "q",
108 Self::RONTO => "r",
109 Self::YOCTO => "y",
110 Self::ZEPTO => "z",
111 Self::ATTO => "a",
112 Self::FEMTO => "f",
113 Self::PICO => "p",
114 Self::NANO => "n",
115 Self::MICRO => "µ",
116 Self::MILLI => "m",
117 Self::CENTI => "c",
118 Self::DECI => "d",
119 Self::NONE => "",
120 Self::DECA => "da",
121 Self::HECTO => "h",
122 Self::KILO => "k",
123 Self::MEGA => "M",
124 Self::GIGA => "G",
125 Self::TERA => "T",
126 Self::PETA => "P",
127 Self::EXA => "E",
128 Self::ZETTA => "Z",
129 Self::YOTTA => "Y",
130 Self::RONNA => "R",
131 Self::QUETTA => "Q",
132 }
133 }
134
135 #[inline(always)]
137 #[must_use]
138 pub const fn exp(&self) -> i8 {
139 *self as i8
140 }
141
142 #[must_use]
145 pub fn from_abbr(abbr: &str) -> Option<Self> {
146 match abbr {
147 "q" => Some(Self::QUECTO),
148 "r" => Some(Self::RONTO),
149 "y" => Some(Self::YOCTO),
150 "z" => Some(Self::ZEPTO),
151 "a" => Some(Self::ATTO),
152 "f" => Some(Self::FEMTO),
153 "p" => Some(Self::PICO),
154 "n" => Some(Self::NANO),
155 "µ" => Some(Self::MICRO),
156 "m" => Some(Self::MILLI),
157 "c" => Some(Self::CENTI),
158 "d" => Some(Self::DECI),
159 "" => Some(Self::NONE),
160 "da" => Some(Self::DECA),
161 "h" => Some(Self::HECTO),
162 "k" => Some(Self::KILO),
163 "M" => Some(Self::MEGA),
164 "G" => Some(Self::GIGA),
165 "T" => Some(Self::TERA),
166 "P" => Some(Self::PETA),
167 "E" => Some(Self::EXA),
168 "Z" => Some(Self::ZETTA),
169 "Y" => Some(Self::YOTTA),
170 "R" => Some(Self::RONNA),
171 "Q" => Some(Self::QUETTA),
172 _ => None,
173 }
174 }
175
176 #[must_use]
179 pub const fn from_exp(exp: i8) -> Option<Self> {
180 match exp {
181 -30 => Some(Self::QUECTO),
182 -27 => Some(Self::RONTO),
183 -24 => Some(Self::YOCTO),
184 -21 => Some(Self::ZEPTO),
185 -18 => Some(Self::ATTO),
186 -15 => Some(Self::FEMTO),
187 -12 => Some(Self::PICO),
188 -9 => Some(Self::NANO),
189 -6 => Some(Self::MICRO),
190 -3 => Some(Self::MILLI),
191 -2 => Some(Self::CENTI),
192 -1 => Some(Self::DECI),
193 0 => Some(Self::NONE),
194 1 => Some(Self::DECA),
195 2 => Some(Self::HECTO),
196 3 => Some(Self::KILO),
197 6 => Some(Self::MEGA),
198 9 => Some(Self::GIGA),
199 12 => Some(Self::TERA),
200 15 => Some(Self::PETA),
201 18 => Some(Self::EXA),
202 21 => Some(Self::ZETTA),
203 24 => Some(Self::YOTTA),
204 27 => Some(Self::RONNA),
205 30 => Some(Self::QUETTA),
206 _ => None,
207 }
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214
215 #[allow(clippy::cognitive_complexity)]
216 #[test]
217 fn test_iter() {
218 let mut it = SIPrefix::iter();
219 assert_eq!(it.next(), Some(&SIPrefix::QUECTO));
220 assert_eq!(it.next(), Some(&SIPrefix::RONTO));
221 assert_eq!(it.next(), Some(&SIPrefix::YOCTO));
222 assert_eq!(it.next(), Some(&SIPrefix::ZEPTO));
223 assert_eq!(it.next(), Some(&SIPrefix::ATTO));
224 assert_eq!(it.next(), Some(&SIPrefix::FEMTO));
225 assert_eq!(it.next(), Some(&SIPrefix::PICO));
226 assert_eq!(it.next(), Some(&SIPrefix::NANO));
227 assert_eq!(it.next(), Some(&SIPrefix::MICRO));
228 assert_eq!(it.next(), Some(&SIPrefix::MILLI));
229 assert_eq!(it.next(), Some(&SIPrefix::CENTI));
230 assert_eq!(it.next(), Some(&SIPrefix::DECI));
231 assert_eq!(it.next(), Some(&SIPrefix::NONE));
232 assert_eq!(it.next(), Some(&SIPrefix::DECA));
233 assert_eq!(it.next(), Some(&SIPrefix::HECTO));
234 assert_eq!(it.next(), Some(&SIPrefix::KILO));
235 assert_eq!(it.next(), Some(&SIPrefix::MEGA));
236 assert_eq!(it.next(), Some(&SIPrefix::GIGA));
237 assert_eq!(it.next(), Some(&SIPrefix::TERA));
238 assert_eq!(it.next(), Some(&SIPrefix::PETA));
239 assert_eq!(it.next(), Some(&SIPrefix::EXA));
240 assert_eq!(it.next(), Some(&SIPrefix::ZETTA));
241 assert_eq!(it.next(), Some(&SIPrefix::YOTTA));
242 assert_eq!(it.next(), Some(&SIPrefix::RONNA));
243 assert_eq!(it.next(), Some(&SIPrefix::QUETTA));
244 assert_eq!(it.next(), None);
245 }
246
247 #[test]
248 fn test_si_prefix_attrs() {
249 let m = SIPrefix::MILLI;
250 assert_eq!(m.name(), "Milli");
251 assert_eq!(m.abbr(), "m");
252 assert_eq!(m.exp(), -3);
253 }
254
255 #[test]
256 fn test_from_abbr() {
257 assert_eq!(SIPrefix::from_abbr("M").unwrap(), SIPrefix::MEGA);
258 assert_eq!(SIPrefix::from_abbr("µ").unwrap(), SIPrefix::MICRO);
259 assert_eq!(SIPrefix::from_abbr("Z").unwrap(), SIPrefix::ZETTA);
260 assert!(SIPrefix::from_abbr("x").is_none());
261 }
262
263 #[test]
264 fn test_from_exp() {
265 assert_eq!(SIPrefix::from_exp(-18).unwrap(), SIPrefix::ATTO);
266 assert_eq!(SIPrefix::from_exp(0).unwrap(), SIPrefix::NONE);
267 assert_eq!(SIPrefix::from_exp(9).unwrap(), SIPrefix::GIGA);
268 assert!(SIPrefix::from_exp(7).is_none());
269 }
270}