1use core::{cmp, fmt, ops};
2
3#[derive(Clone, Copy, Debug)]
88pub struct Voltage {
89 raw: i64,
90}
91
92impl Voltage {
93 #[inline]
98 pub const fn from_micro_volts(value: i64) -> Self {
99 Self { raw: value }
100 }
101
102 #[inline]
104 pub fn micro_volts(&self) -> i64 {
105 self.raw
106 }
107
108 #[inline]
110 pub fn milli_volts(&self) -> f64 {
111 self.raw as f64 / 1_000_f64
112 }
113
114 #[inline]
116 pub fn volts(&self) -> f64 {
117 self.raw as f64 / 1_000_000_f64
118 }
119
120 #[inline]
122 pub fn kilo_volts(&self) -> f64 {
123 self.raw as f64 / 1_000_000_000_f64
124 }
125
126 #[inline]
128 pub const fn is_zero(&self) -> bool {
129 self.raw == 0
130 }
131
132 #[inline]
136 pub const fn is_positive(&self) -> bool {
137 self.raw >= 0
138 }
139
140 #[inline]
144 pub const fn is_negative(&self) -> bool {
145 self.raw < 0
146 }
147
148 #[inline]
150 pub const fn abs(&self) -> Self {
151 Self::from_micro_volts(self.raw.abs())
152 }
153
154 #[inline]
156 pub const fn invert(&self) -> Self {
157 Self::from_micro_volts(self.raw * -1)
158 }
159
160 #[inline]
162 pub const fn zero() -> Self {
163 Self::from_micro_volts(0)
164 }
165}
166
167impl PartialEq for Voltage {
168 #[inline]
169 fn eq(&self, other: &Self) -> bool {
170 self.raw == other.raw
171 }
172}
173
174impl Eq for Voltage {}
175
176impl PartialOrd for Voltage {
177 #[inline]
178 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
179 self.raw.partial_cmp(&other.raw)
180 }
181}
182
183impl Ord for Voltage {
184 #[inline]
185 fn cmp(&self, other: &Self) -> cmp::Ordering {
186 self.raw.cmp(&other.raw)
187 }
188}
189
190impl ops::Add for Voltage {
191 type Output = Self;
192
193 #[inline]
195 fn add(self, other: Self) -> Self {
196 self.raw
197 .checked_add(other.raw)
198 .map(Self::from_micro_volts)
199 .expect("Overflow when adding voltage values")
200 }
201}
202
203impl ops::Sub for Voltage {
204 type Output = Self;
205
206 #[inline]
208 fn sub(self, other: Self) -> Self {
209 self.raw
210 .checked_sub(other.raw)
211 .map(Self::from_micro_volts)
212 .expect("Overflow when subtracting voltage values")
213 }
214}
215
216macro_rules! impl_mul_for_integer {
217 ($i: ty) => {
218 impl ops::Mul<$i> for Voltage {
219 type Output = Self;
220
221 #[inline]
223 fn mul(self, other: $i) -> Self {
224 self.raw
225 .checked_mul(other as i64)
226 .map(Self::from_micro_volts)
227 .expect("Overflow when multiplying voltage value")
228 }
229 }
230 };
231}
232
233impl_mul_for_integer!(u8);
234impl_mul_for_integer!(u16);
235impl_mul_for_integer!(u32);
236impl_mul_for_integer!(u64);
237impl_mul_for_integer!(i8);
238impl_mul_for_integer!(i16);
239impl_mul_for_integer!(i32);
240impl_mul_for_integer!(i64);
241
242impl ops::Mul<f32> for Voltage {
243 type Output = Self;
244
245 #[inline]
247 fn mul(self, scale_factor: f32) -> Self {
248 self * scale_factor as f64
249 }
250}
251
252impl ops::Mul<f64> for Voltage {
253 type Output = Self;
254
255 #[inline]
257 fn mul(self, scale_factor: f64) -> Self {
258 let result = match scale_factor {
259 _ if scale_factor.is_infinite() => {
260 panic!("Cannot multiply voltage value by infinity")
261 }
262 _ if scale_factor.is_nan() => panic!("Cannot multiply voltage value by NaN"),
263 _ => self.raw as f64 * scale_factor,
264 };
265
266 Self::from_micro_volts(result as i64)
267 }
268}
269
270macro_rules! impl_div_for_integer {
271 ($i: ty) => {
272 impl ops::Div<$i> for Voltage {
273 type Output = Self;
274
275 #[inline]
277 fn div(self, divisor: $i) -> Self {
278 if divisor == 0 {
279 panic!("Cannot divide voltage value by zero");
280 }
281 self.raw
282 .checked_div(divisor as i64)
283 .map(Self::from_micro_volts)
284 .expect("Overflow when dividing voltage value")
285 }
286 }
287 };
288}
289
290impl_div_for_integer!(u8);
291impl_div_for_integer!(u16);
292impl_div_for_integer!(u32);
293impl_div_for_integer!(u64);
294impl_div_for_integer!(i8);
295impl_div_for_integer!(i16);
296impl_div_for_integer!(i32);
297impl_div_for_integer!(i64);
298
299impl ops::Div<f32> for Voltage {
300 type Output = Self;
301
302 #[inline]
304 fn div(self, divisor: f32) -> Self {
305 self / divisor as f64
306 }
307}
308
309impl ops::Div<f64> for Voltage {
310 type Output = Self;
311
312 #[inline]
314 fn div(self, divisor: f64) -> Self {
315 let result = match divisor {
316 _ if divisor == 0f64 => panic!("Cannot divide voltage value by zero"),
317 _ if divisor.is_infinite() => {
318 panic!("Cannot divide voltage value by infinity")
319 }
320 _ if divisor.is_nan() => panic!("Cannot divide voltage value by NaN"),
321 _ => (self.raw as f64) / divisor,
322 };
323
324 Self::from_micro_volts(result as i64)
325 }
326}
327
328pub trait FromInteger {
330 fn micro_volts(self) -> Voltage;
332
333 fn milli_volts(self) -> Voltage;
335
336 fn volts(self) -> Voltage;
338
339 fn kilo_volts(self) -> Voltage;
341}
342
343macro_rules! impl_voltage_from_integer {
344 ($i: ty) => {
345 impl FromInteger for $i {
346 #[inline]
347 fn micro_volts(self) -> Voltage {
348 Voltage::from_micro_volts(self as i64)
349 }
350
351 #[inline]
352 fn milli_volts(self) -> Voltage {
353 let microvolts = (self as i64)
354 .checked_mul(1_000)
355 .expect("Overflow when converting millivolts to microvolts");
356 Voltage::from_micro_volts(microvolts)
357 }
358
359 #[inline]
360 fn volts(self) -> Voltage {
361 let microvolts = (self as i64)
362 .checked_mul(1_000_000)
363 .expect("Overflow when converting volts to microvolts");
364 Voltage::from_micro_volts(microvolts)
365 }
366
367 #[inline]
368 fn kilo_volts(self) -> Voltage {
369 let microvolts = (self as i64)
370 .checked_mul(1_000_000_000)
371 .expect("Overflow when converting kilovolts to microvolts");
372 Voltage::from_micro_volts(microvolts)
373 }
374 }
375 };
376}
377
378impl_voltage_from_integer!(u8);
379impl_voltage_from_integer!(u16);
380impl_voltage_from_integer!(u32);
381impl_voltage_from_integer!(u64);
382impl_voltage_from_integer!(i8);
383impl_voltage_from_integer!(i16);
384impl_voltage_from_integer!(i32);
385impl_voltage_from_integer!(i64);
386
387pub trait FromFloat {
389 fn micro_volts(self) -> Voltage;
393
394 fn milli_volts(self) -> Voltage;
398
399 fn volts(self) -> Voltage;
403
404 fn kilo_volts(self) -> Voltage;
408}
409
410macro_rules! impl_voltage_from_float {
411 ($f: ty) => {
412 impl FromFloat for $f {
413 #[inline]
414 fn micro_volts(self) -> Voltage {
415 Voltage::from_micro_volts(self as i64)
416 }
417
418 #[inline]
419 fn milli_volts(self) -> Voltage {
420 let microvolts = (self as f64) * 1_000f64;
421 Voltage::from_micro_volts(microvolts as i64)
422 }
423
424 #[inline]
425 fn volts(self) -> Voltage {
426 let microvolts = (self as f64) * 1_000_000f64;
427 Voltage::from_micro_volts(microvolts as i64)
428 }
429
430 #[inline]
431 fn kilo_volts(self) -> Voltage {
432 let microvolts = (self as f64) * 1_000_000_000f64;
433 Voltage::from_micro_volts(microvolts as i64)
434 }
435 }
436 };
437}
438
439impl_voltage_from_float!(f32);
440impl_voltage_from_float!(f64);
441
442impl fmt::Display for Voltage {
443 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
444 let sign = if self.raw < 0 { "-" } else { "" };
445 let microvolts = self.micro_volts().abs() as f64;
446 let kilovolts = microvolts / 1_000_000_000f64;
447 let volts = microvolts / 1_000_000f64;
448 let millivolts = microvolts / 1_000f64;
449
450 if kilovolts >= 1f64 {
451 write!(f, "{sign}{kilovolts:.2} kV")
452 } else if volts >= 1f64 {
453 write!(f, "{sign}{volts:.2} V")
454 } else if millivolts > 0f64 {
455 write!(f, "{sign}{millivolts:.2} mV")
456 } else {
457 write!(f, "{sign}{microvolts:.2} μV")
458 }
459 }
460}