1use std::fmt;
17
18pub const UNIT_NAMED: u32 = 0xFFFF;
20pub const UNIT_MAX_BUILTIN: u32 = 66;
22
23#[allow(missing_docs)]
27#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
28pub enum UnitTag {
29 Nanoseconds,
31 Microseconds,
32 Milliseconds,
33 Seconds,
34 Minutes,
35 Hours,
36 Days,
37 Weeks,
38 Bytes,
40 Kibibytes,
41 Mebibytes,
42 Gibibytes,
43 Tebibytes,
44 Pebibytes,
45 Exbibytes,
46 Kilobytes,
48 Megabytes,
49 Gigabytes,
50 Terabytes,
51 PerSecond,
53 PerMinute,
54 PerHour,
55 RequestsPerSecond,
56 RequestsPerMinute,
57 RequestsPerHour,
58 Percent,
60 Hertz,
61 Kilohertz,
62 Megahertz,
63 Gigahertz,
64 Terahertz,
65 Bits,
67 Kilobits,
68 Megabits,
69 Gigabits,
70 BitsPerSecond,
71 KilobitsPerSecond,
72 MegabitsPerSecond,
73 GigabitsPerSecond,
74 MegabytesPerSecond,
75 Tokens,
77 KiloTokens,
78 MegaTokens,
79 TokensPerSecond,
80 Flops,
81 TeraFlops,
82 PetaFlops,
83 Pascal,
85 Bar,
86 Psi,
87 Volts,
88 Amperes,
89 Watts,
90 Joules,
91 KilowattHours,
92 Newtons,
93 Degrees,
94 Radians,
95 Rpm,
96 Meters,
97 Kilometers,
98 Kilograms,
99 Grams,
100 Kelvin,
101 Celsius,
102 Fahrenheit,
103 Decibel,
104 Named(String),
106}
107
108impl UnitTag {
109 pub fn discriminant(&self) -> u32 {
112 match self {
113 UnitTag::Nanoseconds => 0,
114 UnitTag::Microseconds => 1,
115 UnitTag::Milliseconds => 2,
116 UnitTag::Seconds => 3,
117 UnitTag::Minutes => 4,
118 UnitTag::Hours => 5,
119 UnitTag::Days => 6,
120 UnitTag::Weeks => 7,
121 UnitTag::Bytes => 8,
122 UnitTag::Kibibytes => 9,
123 UnitTag::Mebibytes => 10,
124 UnitTag::Gibibytes => 11,
125 UnitTag::Tebibytes => 12,
126 UnitTag::Pebibytes => 13,
127 UnitTag::Exbibytes => 14,
128 UnitTag::Kilobytes => 15,
129 UnitTag::Megabytes => 16,
130 UnitTag::Gigabytes => 17,
131 UnitTag::Terabytes => 18,
132 UnitTag::PerSecond => 19,
133 UnitTag::PerMinute => 20,
134 UnitTag::PerHour => 21,
135 UnitTag::RequestsPerSecond => 22,
136 UnitTag::RequestsPerMinute => 23,
137 UnitTag::RequestsPerHour => 24,
138 UnitTag::Percent => 25,
139 UnitTag::Hertz => 26,
140 UnitTag::Kilohertz => 27,
141 UnitTag::Megahertz => 28,
142 UnitTag::Gigahertz => 29,
143 UnitTag::Terahertz => 30,
144 UnitTag::Bits => 31,
145 UnitTag::Kilobits => 32,
146 UnitTag::Megabits => 33,
147 UnitTag::Gigabits => 34,
148 UnitTag::BitsPerSecond => 35,
149 UnitTag::KilobitsPerSecond => 36,
150 UnitTag::MegabitsPerSecond => 37,
151 UnitTag::GigabitsPerSecond => 38,
152 UnitTag::MegabytesPerSecond => 39,
153 UnitTag::Tokens => 40,
154 UnitTag::KiloTokens => 41,
155 UnitTag::MegaTokens => 42,
156 UnitTag::TokensPerSecond => 43,
157 UnitTag::Flops => 44,
158 UnitTag::TeraFlops => 45,
159 UnitTag::PetaFlops => 46,
160 UnitTag::Pascal => 47,
161 UnitTag::Bar => 48,
162 UnitTag::Psi => 49,
163 UnitTag::Volts => 50,
164 UnitTag::Amperes => 51,
165 UnitTag::Watts => 52,
166 UnitTag::Joules => 53,
167 UnitTag::KilowattHours => 54,
168 UnitTag::Newtons => 55,
169 UnitTag::Degrees => 56,
170 UnitTag::Radians => 57,
171 UnitTag::Rpm => 58,
172 UnitTag::Meters => 59,
173 UnitTag::Kilometers => 60,
174 UnitTag::Kilograms => 61,
175 UnitTag::Grams => 62,
176 UnitTag::Kelvin => 63,
177 UnitTag::Celsius => 64,
178 UnitTag::Fahrenheit => 65,
179 UnitTag::Decibel => 66,
180 UnitTag::Named(_) => UNIT_NAMED,
181 }
182 }
183
184 pub fn from_discriminant(disc: u32) -> Option<UnitTag> {
186 let unit = match disc {
187 0 => UnitTag::Nanoseconds,
188 1 => UnitTag::Microseconds,
189 2 => UnitTag::Milliseconds,
190 3 => UnitTag::Seconds,
191 4 => UnitTag::Minutes,
192 5 => UnitTag::Hours,
193 6 => UnitTag::Days,
194 7 => UnitTag::Weeks,
195 8 => UnitTag::Bytes,
196 9 => UnitTag::Kibibytes,
197 10 => UnitTag::Mebibytes,
198 11 => UnitTag::Gibibytes,
199 12 => UnitTag::Tebibytes,
200 13 => UnitTag::Pebibytes,
201 14 => UnitTag::Exbibytes,
202 15 => UnitTag::Kilobytes,
203 16 => UnitTag::Megabytes,
204 17 => UnitTag::Gigabytes,
205 18 => UnitTag::Terabytes,
206 19 => UnitTag::PerSecond,
207 20 => UnitTag::PerMinute,
208 21 => UnitTag::PerHour,
209 22 => UnitTag::RequestsPerSecond,
210 23 => UnitTag::RequestsPerMinute,
211 24 => UnitTag::RequestsPerHour,
212 25 => UnitTag::Percent,
213 26 => UnitTag::Hertz,
214 27 => UnitTag::Kilohertz,
215 28 => UnitTag::Megahertz,
216 29 => UnitTag::Gigahertz,
217 30 => UnitTag::Terahertz,
218 31 => UnitTag::Bits,
219 32 => UnitTag::Kilobits,
220 33 => UnitTag::Megabits,
221 34 => UnitTag::Gigabits,
222 35 => UnitTag::BitsPerSecond,
223 36 => UnitTag::KilobitsPerSecond,
224 37 => UnitTag::MegabitsPerSecond,
225 38 => UnitTag::GigabitsPerSecond,
226 39 => UnitTag::MegabytesPerSecond,
227 40 => UnitTag::Tokens,
228 41 => UnitTag::KiloTokens,
229 42 => UnitTag::MegaTokens,
230 43 => UnitTag::TokensPerSecond,
231 44 => UnitTag::Flops,
232 45 => UnitTag::TeraFlops,
233 46 => UnitTag::PetaFlops,
234 47 => UnitTag::Pascal,
235 48 => UnitTag::Bar,
236 49 => UnitTag::Psi,
237 50 => UnitTag::Volts,
238 51 => UnitTag::Amperes,
239 52 => UnitTag::Watts,
240 53 => UnitTag::Joules,
241 54 => UnitTag::KilowattHours,
242 55 => UnitTag::Newtons,
243 56 => UnitTag::Degrees,
244 57 => UnitTag::Radians,
245 58 => UnitTag::Rpm,
246 59 => UnitTag::Meters,
247 60 => UnitTag::Kilometers,
248 61 => UnitTag::Kilograms,
249 62 => UnitTag::Grams,
250 63 => UnitTag::Kelvin,
251 64 => UnitTag::Celsius,
252 65 => UnitTag::Fahrenheit,
253 66 => UnitTag::Decibel,
254 _ => return None,
255 };
256 Some(unit)
257 }
258
259 pub fn name(&self) -> &str {
261 match self {
262 UnitTag::Nanoseconds => "nanoseconds",
263 UnitTag::Microseconds => "microseconds",
264 UnitTag::Milliseconds => "milliseconds",
265 UnitTag::Seconds => "seconds",
266 UnitTag::Minutes => "minutes",
267 UnitTag::Hours => "hours",
268 UnitTag::Days => "days",
269 UnitTag::Weeks => "weeks",
270 UnitTag::Bytes => "bytes",
271 UnitTag::Kibibytes => "kibibytes",
272 UnitTag::Mebibytes => "mebibytes",
273 UnitTag::Gibibytes => "gibibytes",
274 UnitTag::Tebibytes => "tebibytes",
275 UnitTag::Pebibytes => "pebibytes",
276 UnitTag::Exbibytes => "exbibytes",
277 UnitTag::Kilobytes => "kilobytes",
278 UnitTag::Megabytes => "megabytes",
279 UnitTag::Gigabytes => "gigabytes",
280 UnitTag::Terabytes => "terabytes",
281 UnitTag::PerSecond => "per-second",
282 UnitTag::PerMinute => "per-minute",
283 UnitTag::PerHour => "per-hour",
284 UnitTag::RequestsPerSecond => "requests-per-second",
285 UnitTag::RequestsPerMinute => "requests-per-minute",
286 UnitTag::RequestsPerHour => "requests-per-hour",
287 UnitTag::Percent => "percent",
288 UnitTag::Hertz => "hertz",
289 UnitTag::Kilohertz => "kilohertz",
290 UnitTag::Megahertz => "megahertz",
291 UnitTag::Gigahertz => "gigahertz",
292 UnitTag::Terahertz => "terahertz",
293 UnitTag::Bits => "bits",
294 UnitTag::Kilobits => "kilobits",
295 UnitTag::Megabits => "megabits",
296 UnitTag::Gigabits => "gigabits",
297 UnitTag::BitsPerSecond => "bits-per-second",
298 UnitTag::KilobitsPerSecond => "kilobits-per-second",
299 UnitTag::MegabitsPerSecond => "megabits-per-second",
300 UnitTag::GigabitsPerSecond => "gigabits-per-second",
301 UnitTag::MegabytesPerSecond => "megabytes-per-second",
302 UnitTag::Tokens => "tokens",
303 UnitTag::KiloTokens => "kilo-tokens",
304 UnitTag::MegaTokens => "mega-tokens",
305 UnitTag::TokensPerSecond => "tokens-per-second",
306 UnitTag::Flops => "flops",
307 UnitTag::TeraFlops => "teraflops",
308 UnitTag::PetaFlops => "petaflops",
309 UnitTag::Pascal => "pascal",
310 UnitTag::Bar => "bar",
311 UnitTag::Psi => "psi",
312 UnitTag::Volts => "volts",
313 UnitTag::Amperes => "amperes",
314 UnitTag::Watts => "watts",
315 UnitTag::Joules => "joules",
316 UnitTag::KilowattHours => "kilowatt-hours",
317 UnitTag::Newtons => "newtons",
318 UnitTag::Degrees => "degrees",
319 UnitTag::Radians => "radians",
320 UnitTag::Rpm => "rpm",
321 UnitTag::Meters => "meters",
322 UnitTag::Kilometers => "kilometers",
323 UnitTag::Kilograms => "kilograms",
324 UnitTag::Grams => "grams",
325 UnitTag::Kelvin => "kelvin",
326 UnitTag::Celsius => "celsius",
327 UnitTag::Fahrenheit => "fahrenheit",
328 UnitTag::Decibel => "decibel",
329 UnitTag::Named(name) => name,
330 }
331 }
332
333 pub fn is_non_arithmetic(&self) -> bool {
338 matches!(
339 self,
340 UnitTag::Kelvin | UnitTag::Celsius | UnitTag::Fahrenheit | UnitTag::Decibel
341 )
342 }
343
344 pub fn is_builtin(&self) -> bool {
346 !matches!(self, UnitTag::Named(_))
347 }
348}
349
350impl fmt::Display for UnitTag {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 f.write_str(self.name())
353 }
354}
355
356#[cfg(feature = "active-core")]
357mod interop {
358 use super::UnitTag;
359 use active_core::Unit;
360
361 impl From<&Unit> for UnitTag {
362 fn from(unit: &Unit) -> Self {
363 match unit {
364 Unit::Nanoseconds => UnitTag::Nanoseconds,
365 Unit::Microseconds => UnitTag::Microseconds,
366 Unit::Milliseconds => UnitTag::Milliseconds,
367 Unit::Seconds => UnitTag::Seconds,
368 Unit::Minutes => UnitTag::Minutes,
369 Unit::Hours => UnitTag::Hours,
370 Unit::Days => UnitTag::Days,
371 Unit::Weeks => UnitTag::Weeks,
372 Unit::Bytes => UnitTag::Bytes,
373 Unit::Kibibytes => UnitTag::Kibibytes,
374 Unit::Mebibytes => UnitTag::Mebibytes,
375 Unit::Gibibytes => UnitTag::Gibibytes,
376 Unit::Tebibytes => UnitTag::Tebibytes,
377 Unit::Pebibytes => UnitTag::Pebibytes,
378 Unit::Exbibytes => UnitTag::Exbibytes,
379 Unit::Kilobytes => UnitTag::Kilobytes,
380 Unit::Megabytes => UnitTag::Megabytes,
381 Unit::Gigabytes => UnitTag::Gigabytes,
382 Unit::Terabytes => UnitTag::Terabytes,
383 Unit::PerSecond => UnitTag::PerSecond,
384 Unit::PerMinute => UnitTag::PerMinute,
385 Unit::PerHour => UnitTag::PerHour,
386 Unit::RequestsPerSecond => UnitTag::RequestsPerSecond,
387 Unit::RequestsPerMinute => UnitTag::RequestsPerMinute,
388 Unit::RequestsPerHour => UnitTag::RequestsPerHour,
389 Unit::Percent => UnitTag::Percent,
390 Unit::Hertz => UnitTag::Hertz,
391 Unit::Kilohertz => UnitTag::Kilohertz,
392 Unit::Megahertz => UnitTag::Megahertz,
393 Unit::Gigahertz => UnitTag::Gigahertz,
394 Unit::Terahertz => UnitTag::Terahertz,
395 Unit::Bits => UnitTag::Bits,
396 Unit::Kilobits => UnitTag::Kilobits,
397 Unit::Megabits => UnitTag::Megabits,
398 Unit::Gigabits => UnitTag::Gigabits,
399 Unit::BitsPerSecond => UnitTag::BitsPerSecond,
400 Unit::KilobitsPerSecond => UnitTag::KilobitsPerSecond,
401 Unit::MegabitsPerSecond => UnitTag::MegabitsPerSecond,
402 Unit::GigabitsPerSecond => UnitTag::GigabitsPerSecond,
403 Unit::MegabytesPerSecond => UnitTag::MegabytesPerSecond,
404 Unit::Tokens => UnitTag::Tokens,
405 Unit::KiloTokens => UnitTag::KiloTokens,
406 Unit::MegaTokens => UnitTag::MegaTokens,
407 Unit::TokensPerSecond => UnitTag::TokensPerSecond,
408 Unit::Flops => UnitTag::Flops,
409 Unit::TeraFlops => UnitTag::TeraFlops,
410 Unit::PetaFlops => UnitTag::PetaFlops,
411 Unit::Pascal => UnitTag::Pascal,
412 Unit::Bar => UnitTag::Bar,
413 Unit::Psi => UnitTag::Psi,
414 Unit::Volts => UnitTag::Volts,
415 Unit::Amperes => UnitTag::Amperes,
416 Unit::Watts => UnitTag::Watts,
417 Unit::Joules => UnitTag::Joules,
418 Unit::KilowattHours => UnitTag::KilowattHours,
419 Unit::Newtons => UnitTag::Newtons,
420 Unit::Degrees => UnitTag::Degrees,
421 Unit::Radians => UnitTag::Radians,
422 Unit::Rpm => UnitTag::Rpm,
423 Unit::Meters => UnitTag::Meters,
424 Unit::Kilometers => UnitTag::Kilometers,
425 Unit::Kilograms => UnitTag::Kilograms,
426 Unit::Grams => UnitTag::Grams,
427 Unit::Kelvin => UnitTag::Kelvin,
428 Unit::Celsius => UnitTag::Celsius,
429 Unit::Fahrenheit => UnitTag::Fahrenheit,
430 Unit::Decibel => UnitTag::Decibel,
431 Unit::Custom(name) => UnitTag::Named(name.clone()),
432 }
433 }
434 }
435
436 impl From<&UnitTag> for Unit {
437 fn from(tag: &UnitTag) -> Self {
438 match tag {
439 UnitTag::Nanoseconds => Unit::Nanoseconds,
440 UnitTag::Microseconds => Unit::Microseconds,
441 UnitTag::Milliseconds => Unit::Milliseconds,
442 UnitTag::Seconds => Unit::Seconds,
443 UnitTag::Minutes => Unit::Minutes,
444 UnitTag::Hours => Unit::Hours,
445 UnitTag::Days => Unit::Days,
446 UnitTag::Weeks => Unit::Weeks,
447 UnitTag::Bytes => Unit::Bytes,
448 UnitTag::Kibibytes => Unit::Kibibytes,
449 UnitTag::Mebibytes => Unit::Mebibytes,
450 UnitTag::Gibibytes => Unit::Gibibytes,
451 UnitTag::Tebibytes => Unit::Tebibytes,
452 UnitTag::Pebibytes => Unit::Pebibytes,
453 UnitTag::Exbibytes => Unit::Exbibytes,
454 UnitTag::Kilobytes => Unit::Kilobytes,
455 UnitTag::Megabytes => Unit::Megabytes,
456 UnitTag::Gigabytes => Unit::Gigabytes,
457 UnitTag::Terabytes => Unit::Terabytes,
458 UnitTag::PerSecond => Unit::PerSecond,
459 UnitTag::PerMinute => Unit::PerMinute,
460 UnitTag::PerHour => Unit::PerHour,
461 UnitTag::RequestsPerSecond => Unit::RequestsPerSecond,
462 UnitTag::RequestsPerMinute => Unit::RequestsPerMinute,
463 UnitTag::RequestsPerHour => Unit::RequestsPerHour,
464 UnitTag::Percent => Unit::Percent,
465 UnitTag::Hertz => Unit::Hertz,
466 UnitTag::Kilohertz => Unit::Kilohertz,
467 UnitTag::Megahertz => Unit::Megahertz,
468 UnitTag::Gigahertz => Unit::Gigahertz,
469 UnitTag::Terahertz => Unit::Terahertz,
470 UnitTag::Bits => Unit::Bits,
471 UnitTag::Kilobits => Unit::Kilobits,
472 UnitTag::Megabits => Unit::Megabits,
473 UnitTag::Gigabits => Unit::Gigabits,
474 UnitTag::BitsPerSecond => Unit::BitsPerSecond,
475 UnitTag::KilobitsPerSecond => Unit::KilobitsPerSecond,
476 UnitTag::MegabitsPerSecond => Unit::MegabitsPerSecond,
477 UnitTag::GigabitsPerSecond => Unit::GigabitsPerSecond,
478 UnitTag::MegabytesPerSecond => Unit::MegabytesPerSecond,
479 UnitTag::Tokens => Unit::Tokens,
480 UnitTag::KiloTokens => Unit::KiloTokens,
481 UnitTag::MegaTokens => Unit::MegaTokens,
482 UnitTag::TokensPerSecond => Unit::TokensPerSecond,
483 UnitTag::Flops => Unit::Flops,
484 UnitTag::TeraFlops => Unit::TeraFlops,
485 UnitTag::PetaFlops => Unit::PetaFlops,
486 UnitTag::Pascal => Unit::Pascal,
487 UnitTag::Bar => Unit::Bar,
488 UnitTag::Psi => Unit::Psi,
489 UnitTag::Volts => Unit::Volts,
490 UnitTag::Amperes => Unit::Amperes,
491 UnitTag::Watts => Unit::Watts,
492 UnitTag::Joules => Unit::Joules,
493 UnitTag::KilowattHours => Unit::KilowattHours,
494 UnitTag::Newtons => Unit::Newtons,
495 UnitTag::Degrees => Unit::Degrees,
496 UnitTag::Radians => Unit::Radians,
497 UnitTag::Rpm => Unit::Rpm,
498 UnitTag::Meters => Unit::Meters,
499 UnitTag::Kilometers => Unit::Kilometers,
500 UnitTag::Kilograms => Unit::Kilograms,
501 UnitTag::Grams => Unit::Grams,
502 UnitTag::Kelvin => Unit::Kelvin,
503 UnitTag::Celsius => Unit::Celsius,
504 UnitTag::Fahrenheit => Unit::Fahrenheit,
505 UnitTag::Decibel => Unit::Decibel,
506 UnitTag::Named(name) => Unit::Custom(name.clone()),
507 }
508 }
509 }
510}
511
512#[cfg(test)]
513mod tests {
514 use super::*;
515
516 #[test]
517 fn discriminants_are_bijective() {
518 for disc in 0..=UNIT_MAX_BUILTIN {
519 let unit = UnitTag::from_discriminant(disc).expect("builtin in range");
520 assert_eq!(unit.discriminant(), disc, "round trip for {disc}");
521 assert!(unit.is_builtin());
522 }
523 assert!(UnitTag::from_discriminant(UNIT_MAX_BUILTIN + 1).is_none());
524 assert!(UnitTag::from_discriminant(UNIT_NAMED).is_none());
525 }
526
527 #[test]
528 fn named_units_keep_their_name() {
529 let unit = UnitTag::Named("widgets".to_string());
530 assert_eq!(unit.discriminant(), UNIT_NAMED);
531 assert_eq!(unit.name(), "widgets");
532 assert!(!unit.is_builtin());
533 }
534
535 #[test]
536 fn non_arithmetic_units_match_active_core() {
537 for unit in [
538 UnitTag::Kelvin,
539 UnitTag::Celsius,
540 UnitTag::Fahrenheit,
541 UnitTag::Decibel,
542 ] {
543 assert!(unit.is_non_arithmetic(), "{unit} must be non-arithmetic");
544 }
545 assert!(!UnitTag::Meters.is_non_arithmetic());
546 }
547}