1use core::fmt;
2
3use crate::{base, derived};
4
5impl fmt::Debug for base::BaseUnit {
6 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7 if *self == base::UNITLESS {
8 return write!(f, "BaseUnit::UNITLESS");
9 }
10
11 let components = [
12 (self.kilogram, "kilogram"),
13 (self.meter, "meter"),
14 (self.second, "second"),
15 (self.mole, "mole"),
16 (self.ampere, "ampere"),
17 (self.kelvin, "kelvin"),
18 (self.candela, "candela"),
19 ];
20
21 write!(f, "BaseUnit(")?;
22
23 let mut is_first = true;
24 for (n, symbol) in components {
25 if n != 0 {
26 if !is_first {
27 write!(f, "⋅")?;
28 }
29 write!(f, "{symbol}{}", SignedSuperscript { n })?;
30 is_first = false;
31 }
32 }
33
34 write!(f, ")")
35 }
36}
37
38impl fmt::Display for base::BaseUnit {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 if *self == base::UNITLESS {
41 return write!(f, "Unitless");
42 }
43
44 let components = [
45 (self.kilogram, "kg"),
46 (self.meter, "m"),
47 (self.second, "s"),
48 (self.mole, "mol"),
49 (self.ampere, "A"),
50 (self.kelvin, "K"),
51 (self.candela, "cd"),
52 ];
53
54 let mut is_first = true;
55 for (n, symbol) in components.iter() {
56 let n = *n;
57 if n > 0 {
58 if !is_first {
59 write!(f, "⋅")?;
60 }
61 write!(f, "{symbol}{}", SignedSuperscript { n })?;
62 is_first = false;
63 }
64 }
65
66 let negatives = components.iter().filter(|(n, _)| *n < 0).count();
67 if negatives != 0 {
68 write!(f, "/")?;
69
70 if negatives > 1 {
71 write!(f, "(")?;
72 }
73
74 let mut is_first = true;
75 for (n, symbol) in components.iter() {
76 let n = -*n;
77 if n > 0 {
78 if !is_first {
79 write!(f, "⋅")?;
80 }
81 write!(f, "{symbol}{}", SignedSuperscript { n })?;
82 is_first = false;
83 }
84 }
85
86 if negatives > 1 {
87 write!(f, ")")?;
88 }
89 }
90 Ok(())
91 }
92}
93
94impl<Number> fmt::Display for base::BaseValue<Number>
95where
96 Number: fmt::Display,
97{
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 if self.unit == base::UNITLESS {
100 write!(f, "{}", self.number)
101 } else {
102 write!(f, "{} {}", self.number, self.unit)
103 }
104 }
105}
106
107impl fmt::Debug for derived::DerivedUnit {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109 if *self == derived::UNITLESS {
110 return write!(f, "DerivedUnit::UNITLESS");
111 }
112
113 let components = [
114 (self.base.kilogram, "kilogram"),
115 (self.base.meter, "meter"),
116 (self.base.second, "second"),
117 (self.base.mole, "mole"),
118 (self.base.ampere, "ampere"),
119 (self.base.kelvin, "kelvin"),
120 (self.base.candela, "candela"),
121 (self.hertz, "hertz"),
122 (self.newton, "newton"),
123 (self.pascal, "pascal"),
124 (self.joule, "joule"),
125 (self.watt, "watt"),
126 (self.coulomb, "coulomb"),
127 (self.volt, "volt"),
128 (self.farad, "farad"),
129 (self.ohm, "ohm"),
130 (self.siemens, "siemens"),
131 (self.weber, "weber"),
132 (self.tesla, "tesla"),
133 (self.henry, "henry"),
134 (self.lux, "lux"),
135 (self.becquerel, "becquerel"),
136 (self.gray, "gray"),
137 (self.sievert, "sievert"),
138 (self.katal, "katal"),
139 ];
140
141 write!(f, "DerivedUnit(")?;
142
143 let mut is_first = true;
144 for (n, symbol) in components {
145 if n != 0 {
146 if !is_first {
147 write!(f, "⋅")?;
148 }
149 write!(f, "{symbol}{}", SignedSuperscript { n })?;
150 is_first = false;
151 }
152 }
153
154 write!(f, ")")
155 }
156}
157
158impl fmt::Display for derived::DerivedUnit {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 if *self == derived::UNITLESS {
161 return write!(f, "Unitless");
162 }
163
164 let components = [
165 (self.base.kilogram, "kg"),
166 (self.base.meter, "m"),
167 (self.base.second, "s"),
168 (self.base.mole, "mol"),
169 (self.base.ampere, "A"),
170 (self.base.kelvin, "K"),
171 (self.base.candela, "cd"),
172 (self.hertz, "Hz"),
173 (self.newton, "N"),
174 (self.pascal, "Pa"),
175 (self.joule, "J"),
176 (self.watt, "W"),
177 (self.coulomb, "C"),
178 (self.volt, "V"),
179 (self.farad, "F"),
180 (self.ohm, "Ω"),
181 (self.siemens, "S"),
182 (self.weber, "Wb"),
183 (self.tesla, "T"),
184 (self.henry, "H"),
185 (self.lux, "lx"),
186 (self.becquerel, "Bq"),
187 (self.gray, "Gy"),
188 (self.sievert, "Sv"),
189 (self.katal, "kat"),
190 ];
191
192 let mut is_first = true;
193 for (n, symbol) in components.iter() {
194 let n = *n;
195 if n > 0 {
196 if !is_first {
197 write!(f, "⋅")?;
198 }
199 write!(f, "{symbol}{}", SignedSuperscript { n })?;
200 is_first = false;
201 }
202 }
203
204 let negatives = components.iter().filter(|(n, _)| *n < 0).count();
205 if negatives != 0 {
206 write!(f, "/")?;
207
208 if negatives > 1 {
209 write!(f, "(")?;
210 }
211
212 let mut is_first = true;
213 for (n, symbol) in components.iter() {
214 let n = -*n;
215 if n > 0 {
216 if !is_first {
217 write!(f, "⋅")?;
218 }
219 write!(f, "{symbol}{}", SignedSuperscript { n })?;
220 is_first = false;
221 }
222 }
223
224 if negatives > 1 {
225 write!(f, ")")?;
226 }
227 }
228 Ok(())
229 }
230}
231
232impl<Number> fmt::Display for derived::DerivedValue<Number>
233where
234 Number: fmt::Display,
235{
236 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
237 if self.unit == derived::UNITLESS {
238 write!(f, "{}", self.number)
239 } else {
240 write!(f, "{} {}", self.number, self.unit)
241 }
242 }
243}
244
245struct SignedSuperscript {
246 n: i8,
247}
248
249impl fmt::Display for SignedSuperscript {
250 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251 if self.n == 0 {
252 return write!(f, "⁰");
253 }
254 if self.n == 1 {
255 return Ok(());
256 }
257
258 let n = if self.n < 0 {
260 write!(f, "⁻")?;
261 -self.n as u8
262 } else {
263 self.n as u8
264 };
265
266 let hundreds = n / 100; let n = n - 100 * hundreds;
270 let tens = n / 10; let n = n - 10 * tens;
272 let ones = n; if hundreds != 0 {
275 SuperscriptDigit { digit: hundreds }.fmt(f)?;
276 }
277 if hundreds != 0 || tens != 0 {
278 SuperscriptDigit { digit: tens }.fmt(f)?;
279 }
280 SuperscriptDigit { digit: ones }.fmt(f)?;
281 Ok(())
282 }
283}
284
285struct SuperscriptDigit {
286 digit: u8,
287}
288
289impl fmt::Display for SuperscriptDigit {
290 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
291 match self.digit {
292 0 => write!(f, "⁰"),
293 1 => write!(f, "¹"),
294 2 => write!(f, "²"),
295 3 => write!(f, "³"),
296 4 => write!(f, "⁴"),
297 5 => write!(f, "⁵"),
298 6 => write!(f, "⁶"),
299 7 => write!(f, "⁷"),
300 8 => write!(f, "⁸"),
301 9 => write!(f, "⁹"),
302 _ => unreachable!(),
303 }
304 }
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310
311 #[test]
312 fn test_base_unit_display() {
313 let unit = base::BaseUnit {
314 meter: 1,
315 second: -2,
316 mole: 0,
317 ampere: 0,
318 kelvin: 0,
319 candela: 0,
320 kilogram: 1,
321 };
322 assert_eq!(String::from("kg⋅m/s²"), format!("{}", unit));
323 }
324
325 #[test]
326 fn test_base_value_display() {
327 use crate::base::SECOND;
328 let one_second = base::BaseValue {
330 unit: SECOND,
331 number: 1u32,
332 };
333 assert_eq!(String::from("1 s"), format!("{}", one_second));
334 let two_seconds = base::BaseValue {
335 unit: SECOND,
336 number: 2u32,
337 };
338 assert_eq!(String::from("2 s"), format!("{}", two_seconds));
339 let one_second = base::BaseValue {
341 unit: SECOND,
342 number: 1f32,
343 };
344 assert_eq!(String::from("1 s"), format!("{}", one_second));
345 let two_seconds = base::BaseValue {
346 unit: SECOND,
347 number: 2f32,
348 };
349 assert_eq!(String::from("2 s"), format!("{}", two_seconds));
350 }
351
352 #[test]
353 fn test_derived_unit_display() {
354 let unit = derived::DerivedUnit {
355 farad: 1,
356 sievert: -2,
357 ..derived::UNITLESS
358 };
359 assert_eq!(String::from("F/Sv²"), format!("{}", unit));
360 }
361
362 #[test]
363 fn test_derived_unit_debug() {
364 let unit = derived::DerivedUnit {
365 farad: 1,
366 sievert: -2,
367 ..derived::UNITLESS
368 };
369 assert_eq!(String::from("DerivedUnit(farad⋅sievert⁻²)"), format!("{:?}", unit));
370 }
371
372 #[test]
373 fn test_derived_value_display() {
374 use crate::derived::BECQUEREL;
375 let one_second = derived::DerivedValue {
377 unit: BECQUEREL,
378 number: 1u32,
379 };
380 assert_eq!(String::from("1 Bq"), format!("{}", one_second));
381 let two_seconds = derived::DerivedValue {
382 unit: BECQUEREL,
383 number: 2u32,
384 };
385 assert_eq!(String::from("2 Bq"), format!("{}", two_seconds));
386 let one_second = derived::DerivedValue {
388 unit: BECQUEREL,
389 number: 1f32,
390 };
391 assert_eq!(String::from("1 Bq"), format!("{}", one_second));
392 let two_seconds = derived::DerivedValue {
393 unit: BECQUEREL,
394 number: 2f32,
395 };
396 assert_eq!(String::from("2 Bq"), format!("{}", two_seconds));
397 }
398}