1pub trait IsPlural: PartialEq {
2 fn is_singular(&self) -> bool;
3 fn is_plural(&self) -> bool {
4 !self.is_singular()
5 }
6}
7
8macro_rules ! impl_is_singular {
9 ($($ty:ty: [$pos:literal$(, $neg:literal)?]),*) => {
10 $(
11 impl IsPlural for $ty {
12 fn is_singular(&self) -> bool {
13 if self == &$pos {
14 true
15 }
16 $(
17 else if self == &$neg {
18 true
19 }
20 )?
21 else {
22 false
23 }
24 }
25 }
26 )*
27 }
28}
29
30impl_is_singular!(
31 u8: [1],
32 u16: [1],
33 u32: [1],
34 u64: [1],
35 u128: [1],
36 i8: [1, -1],
37 i16: [1, -1],
38 i32: [1, -1],
39 i64: [1, -1],
40 i128: [1, -1],
41 f32: [1.0, -1.0],
42 f64: [1.0, -1.0]
43);
44
45macro_rules ! unit {
46 {
47 $($name:ident = [$value:literal, $short:expr, $singular:literal, $plural:literal],)*
48 } => {
49 #[derive(Debug, Clone, Copy, PartialEq)]
50 #[repr(u8)]
51 pub enum Unit {
52 $($name = $value,)*
53 Unknown(u8),
54 }
55
56 impl Unit {
57 fn short_display(&self) -> Option<&str> {
58 match self {
59 $(Self::$name => $short,)*
60 Self::Unknown(_) => None,
61 }
62 }
63
64 fn plural_display(&self) -> &str {
65 match self {
66 $(Self::$name => $plural,)*
67 Self::Unknown(_) => "Unknown",
68 }
69 }
70
71 fn singular_display(&self) -> &str {
72 match self {
73 $(Self::$name => $singular,)*
74 Self::Unknown(_) => "Unknown",
75 }
76 }
77
78 fn display_str(&self, short: bool, plural: bool) -> &str
79 {
80 let short_value = if short {
81 self.short_display()
82 } else {
83 None
84 };
85
86 if let Some(short_value) = short_value {
87 short_value
88 } else {
89 if plural {
90 self.plural_display()
91 } else {
92 self.singular_display()
93 }
94 }
95 }
96
97 pub fn display<T>(&self, short: bool, value: T) -> String
98 where T: IsPlural + core::fmt::Display,
99 {
100 format!("{:.2} {}", value, self.display_str(short, value.is_plural()))
101 }
102 }
103
104 impl From<u8> for Unit {
105 fn from(value: u8) -> Self {
106 match value {
107 $($value => Self::$name,)*
108 _ => Self::Unknown(value),
109 }
110 }
111 }
112
113 impl From<Unit> for u8 {
114 fn from(value: Unit) -> Self {
115 match value {
116 $(Unit::$name => $value,)*
117 Unit::Unknown(v) => v,
118 }
119 }
120 }
121
122 }
123}
124
125unit! {
126 Unspecified = [0, None, "Unspecified", "Unspecified"],
127 DegreesCelcius = [1, Some("°C"), "Degree Celcius", "Degrees Celcius"],
128 DegreesFahrenheit = [2, Some("°F"), "Degree Fahrenheit", "Degrees Fahrenheit"],
129 DegreesKelvin = [3, Some("°K"), "Degree Kelvin", "Degrees Kelvin"],
130 Volt = [4, Some("V"), "Volt", "Volts"],
131 Amp = [5, Some("A"), "Ampere", "Amperes"],
132 Watt = [6, Some("W"), "Watt", "Watts"],
133 Joule = [7, Some("J"), "Joule", "Joules"],
134 Coulomb = [8, Some("C"), "Coulomb", "Coulombs"],
135 VoltAmpere = [9, Some("VA"), "Volt-Ampere", "Volt-Amperes"],
136 Nit = [10, None, "Nit", "Nits"],
137 Lumen = [11, Some("lm"), "Lumen", "Lumens"],
138 Lux = [12, Some("lx"), "Lux", "Lux"],
139 Candela = [13, Some("cd"), "Candela", "Candelas"],
140 KiloPascal = [14, Some("kPa"), "Kilopascal", "Kilopascal"],
141 PoundsPerSquareInch = [15, Some("psi"), "Pound per square inch", "Pounds per square inch"],
142 Newton = [16, Some("N"), "Newton", "Newton"],
143 CubicFeetPerMinute = [17, Some("cfm"), "Cubic Foot per Minute", "Cubic Feet per minute"],
144 RevolutionsPerMinute = [18, Some("rpm"), "Revolution per Minute", "Revolutions per Minute"],
145 Hertz = [19, Some("hz"), "Hertz", "Hertz"],
146 Microsecond = [20, Some("µs"), "Microsecond", "Microseconds"],
147 Millisecond = [21, Some("ms"), "Millisecond", "Milliseconds"],
148 Second = [22, Some("s"), "Second", "Seconds"],
149 Minute = [23, Some("min"), "Minute", "Minutes"],
150 Hour = [24, Some("h"), "Hour", "Hours"],
151 Day = [25, Some("d"), "Day", "Days"],
152 Week = [26, Some("w"), "Week", "Weeks"],
153 Mil = [27, Some("mil"), "mil", "mils"],
154 Inch = [28, Some("in"), "Inch", "Inches"],
155 Foot = [29, Some("ft"), "Foot", "Feet"],
156 CubicInch = [30, Some("cu in"), "Cubic Inch", "Cubic Inches"],
157 CubicFoot = [31, Some("cu ft"), "Cubic Foot", "Cubic Feet"],
158 Millimeter = [32, Some("mm"), "Millimeter", "Millimeters"],
159 Centimeter = [33, Some("cm"), "Centimeter", "Centimeters"],
160 Meter = [34, Some("m"), "Meter", "Meters"],
161 CubicCentimeter = [35, Some("cu cm"), "Cubic Centimeter", "Cubic Centimeters"],
162 CubicMeter = [36, Some("cu m"), "Cubic Meter", "Cubic Meters"],
163 Liter = [37, Some("l"), "Liter", "Liters"],
164 FluidOunce = [38, Some("fl oz"), "Fluid Ounce", "Fluid Ounces"],
165 Radian = [39, Some("rad"), "Radian", "Radians"],
166 Steradian = [40, Some("sr"), "Steradian", "Steradians"],
167 Revolution = [41, Some("rev"), "Revolution", "Revolutions"],
168 Cycle = [42, None, "Cycle", "Cycles"],
169 Gravity = [43, Some("Gs (grav)"), "Gravity", "Gravities"],
170 Ounce = [44, Some("oz"), "Ounce", "Ounces"],
171 Pound = [45, Some("lb"), "Pound", "Pounds"],
172 FootPound = [46, Some("ft lb"), "Foot Pound", "Foot Pounds"],
173 OunceInch = [47, Some("oz in"), "Ounce Inch", "Ounce Inches"],
174 Gauss = [48, Some("Gs"), "Gauss", "Gauss"],
175 Gilbert = [49, Some("Gb"), "Gilbert", "Gilbert"],
176 Henry = [50, Some("H"), "Heny", "Heny"],
177 Millihenry = [51, Some("mH"), "Millihenry", "Millihenry"],
178 Farad = [52, Some("F"), "Farad", "Farad"],
179 Microfarad = [53, Some("µF"), "Microfarad", "Microfarad"],
180 Ohm = [54, Some("Ω"), "Ohm", "Ohm"],
181 Siemens = [55, Some("S"), "Siemens", "Siemens"],
182 Mole = [56, Some("mol"), "Mol", "Mol"],
183 Becquerel = [57, Some("Bq"), "Becquerel", "Becquerel"],
184 PartsPerMillion = [58, Some("ppm"), "Part part per million", "Parts per million"],
185 Decibel = [60, Some("dB"), "Decibel", "Decibels"],
186 AWeightedDecibel = [61, Some("dBa"), "A weighted Decibel", "A weighted Decibels"],
187 CWeightedDecibel = [62, Some("dBc"), "C weighted Decibel", "C weighted Decibels"],
188 Gray = [63, Some("Gy"), "Gray", "Gray"],
189 Sievert = [64, Some("Sv"), "Sievert", "Sievert"],
190 ColorTemperatureDegreesKelvin = [65, Some("°K (Color)"), "Degree Kelvin (Color)", "Degrees Kelvin (Color)"],
191 Bit = [66, Some("b"), "Bit", "Bits"],
192 Kilobit = [67, Some("kb"), "Kilobit", "Kilobits"],
193 Megabit = [68, Some("mb"), "Megabit", "Megabits"],
194 Gigabit = [69, Some("Gb"), "Gigabit", "Gigabits"],
195 Byte = [70, Some("B"), "Byte", "Bytes"],
196 Kilobyte = [71, Some("KB"), "Kilobyte", "Kilobytes"],
197 Megabyte = [72, Some("MB"), "Megabyte", "Megabytes"],
198 Gigabyte = [73, Some("GB"), "Gigabyte", "Gigabytes"],
199 Word = [74, None, "Word", "Words"],
200 DoubleWord = [75, None, "Double word", "Double words"],
201 QuadWord = [76, None, "Quad word", "Quad words"],
202 CacheLine = [77, None, "Cache line", "Cache lines"],
203 Hit = [78, None, "Hit", "Hits"],
204 Miss = [79, None, "Miss", "Misses"],
205 Retry = [80, None, "Retry", "Retries"],
206 Reset = [81, None, "Reset", "Resets"],
207 OverrunOrUnderflow = [82, None, "Overrun or Underflow", "Overruns or Underflows"],
208 Underrun = [83, None, "Underrun", "Underruns"],
209 Collision = [84, None, "Collision", "Collisions"],
210 Packet = [85, None, "Packet", "Packets"],
211 Message = [86, None, "Message", "Messges"],
212 Character = [87, None, "Character", "Characters"],
213 Error = [88, None, "Error", "Errors"],
214 CorrectableError = [89, None, "Correctable Error", "Correctable Errors"],
215 UncorrectableError = [90, None, "Uncorrectable Error", "Uncorrectable Errors"],
216 FatalError = [91, None, "Fatal Error", "Fatal Errors"],
217 Gram = [92, Some("gr"), "Gram", "Grams"],
218}
219
220#[test]
221fn display_tests() {
222 use Unit::*;
223
224 assert_eq!("32 °C", DegreesCelcius.display(true, 32));
225 assert_eq!("32 Degrees Celcius", DegreesCelcius.display(false, 32));
226 assert_eq!("1 Degree Celcius", DegreesCelcius.display(false, 1));
227 assert_eq!("-1 Nit", Nit.display(true, -1));
228 assert_eq!("-1 Nit", Nit.display(false, -1));
229 assert_eq!("-15 Nits", Nit.display(false, -15));
230}