1use crate::prefix::Prefix;
46use std::convert::From;
47use std::fmt;
48
49use crate::base::Base;
50use crate::prefix::Constraint;
51
52#[derive(Debug, PartialEq)]
54pub struct Value {
55 pub mantissa: f64,
57
58 pub prefix: Prefix,
60
61 pub base: Base,
63}
64
65impl Value {
66 pub fn new<F>(x: F) -> Self
101 where
102 F: Into<f64>,
103 {
104 Value::new_with(x, Base::B1000, Constraint::None)
105 }
106
107 pub fn new_with<F, C>(x: F, base: Base, prefix_constraint: C) -> Self
130 where
131 F: Into<f64>,
132 C: AsRef<Constraint>,
133 {
134 let x: f64 = x.into();
135
136 let exponent: i32 = base.integral_exponent_for(x);
138 let prefix = Self::closest_prefix_for(exponent, prefix_constraint);
140
141 let mantissa = x / base.pow(prefix.exponent());
142
143 Value {
144 mantissa,
145 base,
146 prefix,
147 }
148 }
149
150 pub fn to_f64(&self) -> f64 {
166 let scale = self.base.pow(self.prefix.exponent());
167 self.mantissa * scale
168 }
169
170 pub fn signum(&self) -> f64 {
189 self.mantissa.signum()
190 }
191
192 fn closest_prefix_for<C: AsRef<Constraint>>(exponent: i32, constraint: C) -> Prefix {
200 use std::convert::TryFrom;
201
202 match constraint.as_ref() {
203 Constraint::None => {
204 Prefix::try_from(exponent.clamp(Prefix::Yocto as i32, Prefix::Yotta as i32))
205 .unwrap_or(Prefix::Unit)
206 }
207 Constraint::UnitOnly => Prefix::Unit,
208 Constraint::UnitAndAbove => {
209 Prefix::try_from(exponent.clamp(Prefix::Unit as i32, Prefix::Yotta as i32))
210 .unwrap_or(Prefix::Unit)
211 }
212 Constraint::UnitAndBelow => {
213 Prefix::try_from(exponent.clamp(Prefix::Yocto as i32, Prefix::Unit as i32))
214 .unwrap_or(Prefix::Unit)
215 }
216 Constraint::Custom(allowed_prefixes) => {
217 if allowed_prefixes.is_empty() {
218 panic!("At least one prefix should be allowed");
219 }
220 let smallest_prefix = *allowed_prefixes.first().unwrap();
221 if exponent < smallest_prefix as i32 {
222 return smallest_prefix;
223 }
224 allowed_prefixes
225 .iter()
226 .take_while(|&&prefix| prefix as i32 <= exponent)
227 .cloned()
228 .last()
229 .unwrap_or(Prefix::Unit)
230 }
231 }
232 }
233}
234
235impl From<Value> for f64 {
240 fn from(value: Value) -> Self {
241 value.to_f64()
242 }
243}
244
245macro_rules! impl_from_num_for_value {
250 ($t:ty) => {
251 impl From<$t> for Value {
252 fn from(x: $t) -> Self {
253 Value::new(x)
254 }
255 }
256
257 impl From<&$t> for Value {
258 fn from(x: &$t) -> Self {
259 Value::new(*x)
260 }
261 }
262 };
263}
264
265impl fmt::Display for Value {
270 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 match self.prefix {
289 Prefix::Unit => write!(f, "{}", self.mantissa),
290 _ => write!(f, "{} {}", self.mantissa, self.prefix),
291 }
292 }
293}
294
295impl_from_num_for_value!(u8);
296impl_from_num_for_value!(i8);
297impl_from_num_for_value!(u16);
298impl_from_num_for_value!(i16);
299impl_from_num_for_value!(u32);
300impl_from_num_for_value!(i32);
301impl_from_num_for_value!(f32);
306impl_from_num_for_value!(f64);
307
308#[cfg(test)]
309mod tests {
310 use super::*;
311
312 #[test]
313 fn out_of_scale_values() {
314 let actual = Value::new(1e-28);
315 let expected = Value {
316 mantissa: 1e-4f64,
317 prefix: Prefix::Yocto,
318 base: Base::B1000,
319 };
320 assert_eq!(actual, expected);
321
322 let actual = Value::new(-1.5e28);
323 let expected = Value {
324 mantissa: -1.5e4f64,
325 prefix: Prefix::Yotta,
326 base: Base::B1000,
327 };
328 assert_eq!(actual, expected);
329 }
330
331 #[test]
332 fn unit_values() {
333 let actual = Value::new(1);
334 let expected = Value {
335 mantissa: 1f64,
336 prefix: Prefix::Unit,
337 base: Base::B1000,
338 };
339 assert_eq!(actual, expected);
340
341 let actual = Value::new(-1.3);
342 let expected = Value {
343 mantissa: -1.3f64,
344 prefix: Prefix::Unit,
345 base: Base::B1000,
346 };
347 assert_eq!(actual, expected);
348 }
349
350 #[test]
351 fn small_values() {
352 let actual = Value::new(0.1);
353 let expected = Value {
354 mantissa: 100f64,
355 prefix: Prefix::Milli,
356 base: Base::B1000,
357 };
358 assert_eq!(actual, expected);
359
360 let actual = Value::new(-0.1);
361 let expected = Value {
362 mantissa: -100f64,
363 prefix: Prefix::Milli,
364 base: Base::B1000,
365 };
366 assert_eq!(actual, expected);
367
368 let actual = Value::new(0.001);
369 let expected = Value {
370 mantissa: 1f64,
371 prefix: Prefix::Milli,
372 base: Base::B1000,
373 };
374 assert_eq!(actual, expected);
375
376 let actual = Value::new(-0.001);
377 let expected = Value {
378 mantissa: -1f64,
379 prefix: Prefix::Milli,
380 base: Base::B1000,
381 };
382 assert_eq!(actual, expected);
383
384 let actual = Value::new(0.000_1);
385 let expected = Value {
386 mantissa: 100.00000000000001f64,
387 prefix: Prefix::Micro,
388 base: Base::B1000,
389 };
390 assert_eq!(actual, expected);
391
392 let actual = Value::new(-0.000_1);
393 let expected = Value {
394 mantissa: -100.00000000000001f64,
395 prefix: Prefix::Micro,
396 base: Base::B1000,
397 };
398 assert_eq!(actual, expected);
399
400 let actual = Value::new(-1e-4);
401 let expected = Value {
402 mantissa: -100.00000000000001f64,
403 prefix: Prefix::Micro,
404 base: Base::B1000,
405 };
406 assert_eq!(actual, expected);
407
408 let actual = Value::new(-1e-8);
409 let expected = Value {
410 mantissa: -10f64,
411 prefix: Prefix::Nano,
412 base: Base::B1000,
413 };
414 assert_eq!(actual, expected);
415
416 let actual = Value::new(-1e-23);
417 let expected = Value {
418 mantissa: -10f64,
419 prefix: Prefix::Yocto,
420 base: Base::B1000,
421 };
422 assert_eq!(actual, expected);
423
424 let actual = Value::new(0.12345);
425 let expected = Value {
426 mantissa: 123.45f64,
427 prefix: Prefix::Milli,
428 base: Base::B1000,
429 };
430 assert_eq!(actual, expected);
431
432 let actual = Value::new(-0.12345);
433 let expected = Value {
434 mantissa: -123.45f64,
435 prefix: Prefix::Milli,
436 base: Base::B1000,
437 };
438 assert_eq!(actual, expected);
439
440 let actual = Value::new(0.01234);
441 let expected = Value {
442 mantissa: 12.34f64,
443 prefix: Prefix::Milli,
444 base: Base::B1000,
445 };
446 assert_eq!(actual, expected);
447
448 let actual = Value::new(-0.01234);
449 let expected = Value {
450 mantissa: -12.34f64,
451 prefix: Prefix::Milli,
452 base: Base::B1000,
453 };
454 assert_eq!(actual, expected);
455
456 let actual = Value::new(0.001234);
457 let expected = Value {
458 mantissa: 1.234f64,
459 prefix: Prefix::Milli,
460 base: Base::B1000,
461 };
462 assert_eq!(actual, expected);
463
464 let actual = Value::new(-0.001234);
465 let expected = Value {
466 mantissa: -1.234f64,
467 prefix: Prefix::Milli,
468 base: Base::B1000,
469 };
470 assert_eq!(actual, expected);
471
472 let actual = Value::new(0.000_123_400);
473 let expected = Value {
474 mantissa: 123.39999999999999f64,
475 prefix: Prefix::Micro,
476 base: Base::B1000,
477 };
478 assert_eq!(actual, expected);
479
480 let actual = Value::new(-0.000_123_400);
481 let expected = Value {
482 mantissa: -123.39999999999999f64,
483 prefix: Prefix::Micro,
484 base: Base::B1000,
485 };
486 assert_eq!(actual, expected);
487 }
488
489 #[test]
490 fn large_values() {
491 let actual = Value::new(1234);
492 let expected = Value {
493 mantissa: 1.234f64,
494 prefix: Prefix::Kilo,
495 base: Base::B1000,
496 };
497 assert_eq!(actual, expected);
498
499 let actual = Value::new(123_456);
500 let expected = Value {
501 mantissa: 123.456f64,
502 prefix: Prefix::Kilo,
503 base: Base::B1000,
504 };
505 assert_eq!(actual, expected);
506
507 let actual = Value::new(123_456_000);
508 let expected = Value {
509 mantissa: 123.456f64,
510 prefix: Prefix::Mega,
511 base: Base::B1000,
512 };
513 assert_eq!(actual, expected);
514
515 let actual = Value::new(-123_456_000);
516 let expected = Value {
517 mantissa: -123.456f64,
518 prefix: Prefix::Mega,
519 base: Base::B1000,
520 };
521 assert_eq!(actual, expected);
522 }
523
524 #[test]
525 fn from_numbers() {
526 let actual = Value::from(0.1f32);
527 let expected = Value {
528 mantissa: 100.00000149011612f64,
529 prefix: Prefix::Milli,
530 base: Base::B1000,
531 };
532 assert_eq!(actual, expected);
533
534 let actual = Value::from(-0.1);
535 let expected = Value {
536 mantissa: -100f64,
537 prefix: Prefix::Milli,
538 base: Base::B1000,
539 };
540 assert_eq!(actual, expected);
541
542 let actual = Value::from(1.5);
543 let expected = Value {
544 mantissa: 1.5f64,
545 prefix: Prefix::Unit,
546 base: Base::B1000,
547 };
548 assert_eq!(actual, expected);
549
550 let actual = Value::from(-1.5);
551 let expected = Value {
552 mantissa: -1.5f64,
553 prefix: Prefix::Unit,
554 base: Base::B1000,
555 };
556 assert_eq!(actual, expected);
557
558 let actual = Value::from(15u32);
559 let expected = Value {
560 mantissa: 15f64,
561 prefix: Prefix::Unit,
562 base: Base::B1000,
563 };
564 assert_eq!(actual, expected);
565
566 let actual = Value::from(-1.5e28);
567 let expected = Value {
568 mantissa: -1.5e4f64,
569 prefix: Prefix::Yotta,
570 base: Base::B1000,
571 };
572 assert_eq!(actual, expected);
573 }
574
575 #[test]
576 fn from_ref_number() {
577 let number = 0.1;
578 let actual = Value::from(&number);
579 let expected = Value {
580 mantissa: 100f64,
581 prefix: Prefix::Milli,
582 base: Base::B1000,
583 };
584 assert_eq!(actual, expected);
585
586 let number = 10_000_000u32;
587 let actual = Value::from(&number);
588 let expected = Value {
589 mantissa: 10f64,
590 prefix: Prefix::Mega,
591 base: Base::B1000,
592 };
593 assert_eq!(actual, expected);
594 }
595
596 #[test]
597 fn into_f64() {
598 let x = 0.1;
599 let actual: f64 = Value::from(x).into();
600 let expected = x;
601 assert_eq!(actual, expected);
602
603 let x = -0.1;
604 let actual: f64 = Value::from(x).into();
605 let expected = x;
606 assert_eq!(actual, expected);
607
608 let x = 1.500;
609 let actual: f64 = Value::from(x).into();
610 let expected = x;
611 assert_eq!(actual, expected);
612
613 let x = -1.500;
614 let actual: f64 = Value::from(x).into();
615 let expected = x;
616 assert_eq!(actual, expected);
617 }
618
619 #[test]
620 fn large_value_with_base_1024() {
621 let actual = Value::new_with(1, Base::B1024, Constraint::None);
622 let expected = Value {
623 mantissa: 1f64,
624 prefix: Prefix::Unit,
625 base: Base::B1024,
626 };
627 assert_eq!(actual, expected);
628
629 let actual = Value::new_with(16, Base::B1024, Constraint::None);
630 let expected = Value {
631 mantissa: 16f64,
632 prefix: Prefix::Unit,
633 base: Base::B1024,
634 };
635 assert_eq!(actual, expected);
636
637 let actual = Value::new_with(1024, Base::B1024, Constraint::None);
638 let expected = Value {
639 mantissa: 1f64,
640 prefix: Prefix::Kilo,
641 base: Base::B1024,
642 };
643 assert_eq!(actual, expected);
644
645 let actual = Value::new_with(1.6 * 1024f32, Base::B1024, Constraint::None);
646 let expected = Value {
647 mantissa: 1.600000023841858f64,
648 prefix: Prefix::Kilo,
649 base: Base::B1024,
650 };
651 assert_eq!(actual, expected);
652
653 let actual = Value::new_with(16 * 1024 * 1024, Base::B1024, Constraint::None);
654 let expected = Value {
655 mantissa: 16f64,
656 prefix: Prefix::Mega,
657 base: Base::B1024,
658 };
659 assert_eq!(actual, expected);
660 }
661
662 #[test]
663 fn values_with_prefix_constraints() {
664 let actual = Value::new_with(1325, Base::B1000, Constraint::UnitAndBelow);
667 let expected = Value {
668 mantissa: 1325f64,
669 prefix: Prefix::Unit,
670 base: Base::B1000,
671 };
672 assert_eq!(actual, expected);
673
674 let actual = Value::new_with(0.015, Base::B1024, Constraint::UnitAndAbove);
676 let expected = Value {
677 mantissa: 0.015,
678 prefix: Prefix::Unit,
679 base: Base::B1024,
680 };
681 assert_eq!(actual, expected);
682
683 let actual = Value::new_with(0.015, Base::B1000, Constraint::UnitOnly);
685 let expected = Value {
686 mantissa: 0.015,
687 prefix: Prefix::Unit,
688 base: Base::B1000,
689 };
690 assert_eq!(actual, expected);
691 }
692
693 #[test]
697 fn closest_prefix_without_constraint() {
698 let exponent = -24;
699 let actual = Value::closest_prefix_for(exponent, Constraint::None);
700 let expected = Prefix::Yocto;
701 assert_eq!(actual, expected);
702
703 let exponent = 0;
704 let actual = Value::closest_prefix_for(exponent, Constraint::None);
705 let expected = Prefix::Unit;
706 assert_eq!(actual, expected);
707
708 let exponent = 24;
709 let actual = Value::closest_prefix_for(exponent, Constraint::None);
710 let expected = Prefix::Yotta;
711 assert_eq!(actual, expected);
712
713 let exponent = 30;
714 let actual = Value::closest_prefix_for(exponent, Constraint::None);
715 let expected = Prefix::Yotta;
716 assert_eq!(actual, expected);
717
718 let exponent = 1; let actual = Value::closest_prefix_for(exponent, Constraint::None);
720 let expected = Prefix::Unit;
721 assert_eq!(actual, expected);
722 }
723
724 #[test]
728 fn closest_prefix_with_unitandabove() {
729 let constraint = Constraint::UnitAndAbove;
730
731 let exponent = -24;
732 let actual = Value::closest_prefix_for(exponent, &constraint);
733 let expected = Prefix::Unit;
734 assert_eq!(actual, expected);
735
736 let exponent = 0;
737 let actual = Value::closest_prefix_for(exponent, &constraint);
738 let expected = Prefix::Unit;
739 assert_eq!(actual, expected);
740
741 let exponent = 24;
742 let actual = Value::closest_prefix_for(exponent, &constraint);
743 let expected = Prefix::Yotta;
744 assert_eq!(actual, expected);
745
746 let exponent = 30;
747 let actual = Value::closest_prefix_for(exponent, &constraint);
748 let expected = Prefix::Yotta;
749 assert_eq!(actual, expected);
750
751 let exponent = 1; let actual = Value::closest_prefix_for(exponent, &constraint);
753 let expected = Prefix::Unit;
754 assert_eq!(actual, expected);
755 }
756
757 #[test]
761 fn closest_prefix_with_unitandbelow() {
762 let constraint = Constraint::UnitAndBelow;
763
764 let exponent = -24;
765 let actual = Value::closest_prefix_for(exponent, &constraint);
766 let expected = Prefix::Yocto;
767 assert_eq!(actual, expected);
768
769 let exponent = 0;
770 let actual = Value::closest_prefix_for(exponent, &constraint);
771 let expected = Prefix::Unit;
772 assert_eq!(actual, expected);
773
774 let exponent = 24;
775 let actual = Value::closest_prefix_for(exponent, &constraint);
776 let expected = Prefix::Unit;
777 assert_eq!(actual, expected);
778
779 let exponent = -30;
780 let actual = Value::closest_prefix_for(exponent, &constraint);
781 let expected = Prefix::Yocto;
782 assert_eq!(actual, expected);
783
784 let exponent = -1; let actual = Value::closest_prefix_for(exponent, &constraint);
786 let expected = Prefix::Unit;
787 assert_eq!(actual, expected);
788 }
789
790 #[test]
793 fn closest_prefix_with_custom() {
794 let constraint = Constraint::Custom(vec![Prefix::Milli, Prefix::Unit, Prefix::Kilo]);
795
796 let exponent = -24;
797 let actual = Value::closest_prefix_for(exponent, &constraint);
798 let expected = Prefix::Milli;
799 assert_eq!(actual, expected);
800
801 let exponent = -3;
802 let actual = Value::closest_prefix_for(exponent, &constraint);
803 let expected = Prefix::Milli;
804 assert_eq!(actual, expected);
805
806 let exponent = 0;
807 let actual = Value::closest_prefix_for(exponent, &constraint);
808 let expected = Prefix::Unit;
809 assert_eq!(actual, expected);
810
811 let exponent = 3;
812 let actual = Value::closest_prefix_for(exponent, &constraint);
813 let expected = Prefix::Kilo;
814 assert_eq!(actual, expected);
815
816 let exponent = 24;
817 let actual = Value::closest_prefix_for(exponent, &constraint);
818 let expected = Prefix::Kilo;
819 assert_eq!(actual, expected);
820
821 let exponent = -30;
822 let actual = Value::closest_prefix_for(exponent, &constraint);
823 let expected = Prefix::Milli;
824 assert_eq!(actual, expected);
825
826 let exponent = -1; let actual = Value::closest_prefix_for(exponent, &constraint);
828 let expected = Prefix::Milli;
829 assert_eq!(actual, expected);
830 }
831
832 #[test]
833 #[should_panic]
834 fn closest_prefix_with_custom_empty() {
835 let constraint = Constraint::Custom(vec![]);
836
837 let exponent = 3;
838 Value::closest_prefix_for(exponent, constraint);
839 }
840}