1use crate::prefix::Prefix;
46use std::convert::From;
47use std::fmt;
48
49use crate::base::Base;
50use crate::prefix::Constraint;
51
52#[diagnostic::on_unimplemented(
58 message = "`{Self}` cannot be converted to `f64`",
59 label = "this type doesn't implement `IntoF64`",
60 note = "for `u64`, `i64`, `usize`, or `isize`, enable the `lossy-conversions` feature"
61)]
62pub trait IntoF64 {
63 fn into_f64(self) -> f64;
65}
66
67macro_rules! impl_into_f64_lossless {
68 ($($t:ty),*) => {
69 $(
70 impl IntoF64 for $t {
71 #[inline]
72 fn into_f64(self) -> f64 {
73 self.into()
74 }
75 }
76 )*
77 };
78}
79
80impl_into_f64_lossless!(u8, i8, u16, i16, u32, i32, f32, f64);
81
82#[cfg(feature = "lossy-conversions")]
83macro_rules! impl_into_f64_lossy {
84 ($($t:ty),*) => {
85 $(
86 impl IntoF64 for $t {
87 #[inline]
88 fn into_f64(self) -> f64 {
89 self as f64
90 }
91 }
92 )*
93 };
94}
95
96#[cfg(feature = "lossy-conversions")]
97impl_into_f64_lossy!(u64, i64, usize, isize);
98
99#[derive(Debug, PartialEq)]
101pub struct Value {
102 pub mantissa: f64,
104
105 pub prefix: Prefix,
107
108 pub base: Base,
110}
111
112impl Value {
113 pub fn new<F>(x: F) -> Self
148 where
149 F: IntoF64,
150 {
151 Value::new_with(x, Base::B1000, Constraint::None)
152 }
153
154 pub fn new_with<F, C>(x: F, base: Base, prefix_constraint: C) -> Self
177 where
178 F: IntoF64,
179 C: AsRef<Constraint>,
180 {
181 let x: f64 = x.into_f64();
182
183 let exponent: i32 = base.integral_exponent_for(x);
185 let prefix = Self::closest_prefix_for(exponent, prefix_constraint);
187
188 let mantissa = x / base.pow(prefix.exponent());
189
190 Value {
191 mantissa,
192 base,
193 prefix,
194 }
195 }
196
197 pub fn to_f64(&self) -> f64 {
213 let scale = self.base.pow(self.prefix.exponent());
214 self.mantissa * scale
215 }
216
217 pub fn signum(&self) -> f64 {
236 self.mantissa.signum()
237 }
238
239 fn closest_prefix_for<C: AsRef<Constraint>>(exponent: i32, constraint: C) -> Prefix {
247 use std::convert::TryFrom;
248
249 match constraint.as_ref() {
250 Constraint::None => {
251 Prefix::try_from(exponent.clamp(Prefix::Yocto as i32, Prefix::Yotta as i32))
252 .unwrap_or(Prefix::Unit)
253 }
254 Constraint::UnitOnly => Prefix::Unit,
255 Constraint::UnitAndAbove => {
256 Prefix::try_from(exponent.clamp(Prefix::Unit as i32, Prefix::Yotta as i32))
257 .unwrap_or(Prefix::Unit)
258 }
259 Constraint::UnitAndBelow => {
260 Prefix::try_from(exponent.clamp(Prefix::Yocto as i32, Prefix::Unit as i32))
261 .unwrap_or(Prefix::Unit)
262 }
263 Constraint::Custom(allowed_prefixes) => {
264 if allowed_prefixes.is_empty() {
265 panic!("At least one prefix should be allowed");
266 }
267 let smallest_prefix = *allowed_prefixes.first().unwrap();
268 if exponent < smallest_prefix as i32 {
269 return smallest_prefix;
270 }
271 allowed_prefixes
272 .iter()
273 .take_while(|&&prefix| prefix as i32 <= exponent)
274 .cloned()
275 .last()
276 .unwrap_or(Prefix::Unit)
277 }
278 }
279 }
280}
281
282impl From<Value> for f64 {
287 fn from(value: Value) -> Self {
288 value.to_f64()
289 }
290}
291
292macro_rules! impl_from_num_for_value {
297 ($t:ty) => {
298 impl From<$t> for Value {
299 fn from(x: $t) -> Self {
300 Value::new(x)
301 }
302 }
303
304 impl From<&$t> for Value {
305 fn from(x: &$t) -> Self {
306 Value::new(*x)
307 }
308 }
309 };
310}
311
312impl fmt::Display for Value {
317 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335 match self.prefix {
336 Prefix::Unit => write!(f, "{}", self.mantissa),
337 _ => write!(f, "{} {}", self.mantissa, self.prefix),
338 }
339 }
340}
341
342impl_from_num_for_value!(u8);
343impl_from_num_for_value!(i8);
344impl_from_num_for_value!(u16);
345impl_from_num_for_value!(i16);
346impl_from_num_for_value!(u32);
347impl_from_num_for_value!(i32);
348impl_from_num_for_value!(f32);
349impl_from_num_for_value!(f64);
350
351#[cfg(feature = "lossy-conversions")]
352impl_from_num_for_value!(u64);
353#[cfg(feature = "lossy-conversions")]
354impl_from_num_for_value!(i64);
355#[cfg(feature = "lossy-conversions")]
356impl_from_num_for_value!(usize);
357#[cfg(feature = "lossy-conversions")]
358impl_from_num_for_value!(isize);
359
360#[cfg(test)]
361mod tests {
362 use super::*;
363
364 #[test]
365 fn out_of_scale_values() {
366 let actual = Value::new(1e-28);
367 let expected = Value {
368 mantissa: 1e-4f64,
369 prefix: Prefix::Yocto,
370 base: Base::B1000,
371 };
372 assert_eq!(actual, expected);
373
374 let actual = Value::new(-1.5e28);
375 let expected = Value {
376 mantissa: -1.5e4f64,
377 prefix: Prefix::Yotta,
378 base: Base::B1000,
379 };
380 assert_eq!(actual, expected);
381 }
382
383 #[test]
384 fn unit_values() {
385 let actual = Value::new(1);
386 let expected = Value {
387 mantissa: 1f64,
388 prefix: Prefix::Unit,
389 base: Base::B1000,
390 };
391 assert_eq!(actual, expected);
392
393 let actual = Value::new(-1.3);
394 let expected = Value {
395 mantissa: -1.3f64,
396 prefix: Prefix::Unit,
397 base: Base::B1000,
398 };
399 assert_eq!(actual, expected);
400 }
401
402 #[test]
403 fn small_values() {
404 let actual = Value::new(0.1);
405 let expected = Value {
406 mantissa: 100f64,
407 prefix: Prefix::Milli,
408 base: Base::B1000,
409 };
410 assert_eq!(actual, expected);
411
412 let actual = Value::new(-0.1);
413 let expected = Value {
414 mantissa: -100f64,
415 prefix: Prefix::Milli,
416 base: Base::B1000,
417 };
418 assert_eq!(actual, expected);
419
420 let actual = Value::new(0.001);
421 let expected = Value {
422 mantissa: 1f64,
423 prefix: Prefix::Milli,
424 base: Base::B1000,
425 };
426 assert_eq!(actual, expected);
427
428 let actual = Value::new(-0.001);
429 let expected = Value {
430 mantissa: -1f64,
431 prefix: Prefix::Milli,
432 base: Base::B1000,
433 };
434 assert_eq!(actual, expected);
435
436 let actual = Value::new(0.000_1);
437 let expected = Value {
438 mantissa: 100.00000000000001f64,
439 prefix: Prefix::Micro,
440 base: Base::B1000,
441 };
442 assert_eq!(actual, expected);
443
444 let actual = Value::new(-0.000_1);
445 let expected = Value {
446 mantissa: -100.00000000000001f64,
447 prefix: Prefix::Micro,
448 base: Base::B1000,
449 };
450 assert_eq!(actual, expected);
451
452 let actual = Value::new(-1e-4);
453 let expected = Value {
454 mantissa: -100.00000000000001f64,
455 prefix: Prefix::Micro,
456 base: Base::B1000,
457 };
458 assert_eq!(actual, expected);
459
460 let actual = Value::new(-1e-8);
461 let expected = Value {
462 mantissa: -10f64,
463 prefix: Prefix::Nano,
464 base: Base::B1000,
465 };
466 assert_eq!(actual, expected);
467
468 let actual = Value::new(-1e-23);
469 let expected = Value {
470 mantissa: -10f64,
471 prefix: Prefix::Yocto,
472 base: Base::B1000,
473 };
474 assert_eq!(actual, expected);
475
476 let actual = Value::new(0.12345);
477 let expected = Value {
478 mantissa: 123.45f64,
479 prefix: Prefix::Milli,
480 base: Base::B1000,
481 };
482 assert_eq!(actual, expected);
483
484 let actual = Value::new(-0.12345);
485 let expected = Value {
486 mantissa: -123.45f64,
487 prefix: Prefix::Milli,
488 base: Base::B1000,
489 };
490 assert_eq!(actual, expected);
491
492 let actual = Value::new(0.01234);
493 let expected = Value {
494 mantissa: 12.34f64,
495 prefix: Prefix::Milli,
496 base: Base::B1000,
497 };
498 assert_eq!(actual, expected);
499
500 let actual = Value::new(-0.01234);
501 let expected = Value {
502 mantissa: -12.34f64,
503 prefix: Prefix::Milli,
504 base: Base::B1000,
505 };
506 assert_eq!(actual, expected);
507
508 let actual = Value::new(0.001234);
509 let expected = Value {
510 mantissa: 1.234f64,
511 prefix: Prefix::Milli,
512 base: Base::B1000,
513 };
514 assert_eq!(actual, expected);
515
516 let actual = Value::new(-0.001234);
517 let expected = Value {
518 mantissa: -1.234f64,
519 prefix: Prefix::Milli,
520 base: Base::B1000,
521 };
522 assert_eq!(actual, expected);
523
524 let actual = Value::new(0.000_123_400);
525 let expected = Value {
526 mantissa: 123.39999999999999f64,
527 prefix: Prefix::Micro,
528 base: Base::B1000,
529 };
530 assert_eq!(actual, expected);
531
532 let actual = Value::new(-0.000_123_400);
533 let expected = Value {
534 mantissa: -123.39999999999999f64,
535 prefix: Prefix::Micro,
536 base: Base::B1000,
537 };
538 assert_eq!(actual, expected);
539 }
540
541 #[test]
542 fn large_values() {
543 let actual = Value::new(1234);
544 let expected = Value {
545 mantissa: 1.234f64,
546 prefix: Prefix::Kilo,
547 base: Base::B1000,
548 };
549 assert_eq!(actual, expected);
550
551 let actual = Value::new(123_456);
552 let expected = Value {
553 mantissa: 123.456f64,
554 prefix: Prefix::Kilo,
555 base: Base::B1000,
556 };
557 assert_eq!(actual, expected);
558
559 let actual = Value::new(123_456_000);
560 let expected = Value {
561 mantissa: 123.456f64,
562 prefix: Prefix::Mega,
563 base: Base::B1000,
564 };
565 assert_eq!(actual, expected);
566
567 let actual = Value::new(-123_456_000);
568 let expected = Value {
569 mantissa: -123.456f64,
570 prefix: Prefix::Mega,
571 base: Base::B1000,
572 };
573 assert_eq!(actual, expected);
574 }
575
576 #[test]
577 fn from_numbers() {
578 let actual = Value::from(0.1f32);
579 let expected = Value {
580 mantissa: 100.00000149011612f64,
581 prefix: Prefix::Milli,
582 base: Base::B1000,
583 };
584 assert_eq!(actual, expected);
585
586 let actual = Value::from(-0.1);
587 let expected = Value {
588 mantissa: -100f64,
589 prefix: Prefix::Milli,
590 base: Base::B1000,
591 };
592 assert_eq!(actual, expected);
593
594 let actual = Value::from(1.5);
595 let expected = Value {
596 mantissa: 1.5f64,
597 prefix: Prefix::Unit,
598 base: Base::B1000,
599 };
600 assert_eq!(actual, expected);
601
602 let actual = Value::from(-1.5);
603 let expected = Value {
604 mantissa: -1.5f64,
605 prefix: Prefix::Unit,
606 base: Base::B1000,
607 };
608 assert_eq!(actual, expected);
609
610 let actual = Value::from(15u32);
611 let expected = Value {
612 mantissa: 15f64,
613 prefix: Prefix::Unit,
614 base: Base::B1000,
615 };
616 assert_eq!(actual, expected);
617
618 let actual = Value::from(-1.5e28);
619 let expected = Value {
620 mantissa: -1.5e4f64,
621 prefix: Prefix::Yotta,
622 base: Base::B1000,
623 };
624 assert_eq!(actual, expected);
625 }
626
627 #[test]
628 fn from_ref_number() {
629 let number = 0.1;
630 let actual = Value::from(&number);
631 let expected = Value {
632 mantissa: 100f64,
633 prefix: Prefix::Milli,
634 base: Base::B1000,
635 };
636 assert_eq!(actual, expected);
637
638 let number = 10_000_000u32;
639 let actual = Value::from(&number);
640 let expected = Value {
641 mantissa: 10f64,
642 prefix: Prefix::Mega,
643 base: Base::B1000,
644 };
645 assert_eq!(actual, expected);
646 }
647
648 #[test]
649 fn into_f64() {
650 let x = 0.1;
651 let actual: f64 = Value::from(x).into();
652 let expected = x;
653 assert_eq!(actual, expected);
654
655 let x = -0.1;
656 let actual: f64 = Value::from(x).into();
657 let expected = x;
658 assert_eq!(actual, expected);
659
660 let x = 1.500;
661 let actual: f64 = Value::from(x).into();
662 let expected = x;
663 assert_eq!(actual, expected);
664
665 let x = -1.500;
666 let actual: f64 = Value::from(x).into();
667 let expected = x;
668 assert_eq!(actual, expected);
669 }
670
671 #[test]
672 fn large_value_with_base_1024() {
673 let actual = Value::new_with(1, Base::B1024, Constraint::None);
674 let expected = Value {
675 mantissa: 1f64,
676 prefix: Prefix::Unit,
677 base: Base::B1024,
678 };
679 assert_eq!(actual, expected);
680
681 let actual = Value::new_with(16, Base::B1024, Constraint::None);
682 let expected = Value {
683 mantissa: 16f64,
684 prefix: Prefix::Unit,
685 base: Base::B1024,
686 };
687 assert_eq!(actual, expected);
688
689 let actual = Value::new_with(1024, Base::B1024, Constraint::None);
690 let expected = Value {
691 mantissa: 1f64,
692 prefix: Prefix::Kilo,
693 base: Base::B1024,
694 };
695 assert_eq!(actual, expected);
696
697 let actual = Value::new_with(1.6 * 1024f32, Base::B1024, Constraint::None);
698 let expected = Value {
699 mantissa: 1.600000023841858f64,
700 prefix: Prefix::Kilo,
701 base: Base::B1024,
702 };
703 assert_eq!(actual, expected);
704
705 let actual = Value::new_with(16 * 1024 * 1024, Base::B1024, Constraint::None);
706 let expected = Value {
707 mantissa: 16f64,
708 prefix: Prefix::Mega,
709 base: Base::B1024,
710 };
711 assert_eq!(actual, expected);
712 }
713
714 #[test]
715 fn values_with_prefix_constraints() {
716 let actual = Value::new_with(1325, Base::B1000, Constraint::UnitAndBelow);
719 let expected = Value {
720 mantissa: 1325f64,
721 prefix: Prefix::Unit,
722 base: Base::B1000,
723 };
724 assert_eq!(actual, expected);
725
726 let actual = Value::new_with(0.015, Base::B1024, Constraint::UnitAndAbove);
728 let expected = Value {
729 mantissa: 0.015,
730 prefix: Prefix::Unit,
731 base: Base::B1024,
732 };
733 assert_eq!(actual, expected);
734
735 let actual = Value::new_with(0.015, Base::B1000, Constraint::UnitOnly);
737 let expected = Value {
738 mantissa: 0.015,
739 prefix: Prefix::Unit,
740 base: Base::B1000,
741 };
742 assert_eq!(actual, expected);
743 }
744
745 #[test]
749 fn closest_prefix_without_constraint() {
750 let exponent = -24;
751 let actual = Value::closest_prefix_for(exponent, Constraint::None);
752 let expected = Prefix::Yocto;
753 assert_eq!(actual, expected);
754
755 let exponent = 0;
756 let actual = Value::closest_prefix_for(exponent, Constraint::None);
757 let expected = Prefix::Unit;
758 assert_eq!(actual, expected);
759
760 let exponent = 24;
761 let actual = Value::closest_prefix_for(exponent, Constraint::None);
762 let expected = Prefix::Yotta;
763 assert_eq!(actual, expected);
764
765 let exponent = 30;
766 let actual = Value::closest_prefix_for(exponent, Constraint::None);
767 let expected = Prefix::Yotta;
768 assert_eq!(actual, expected);
769
770 let exponent = 1; let actual = Value::closest_prefix_for(exponent, Constraint::None);
772 let expected = Prefix::Unit;
773 assert_eq!(actual, expected);
774 }
775
776 #[test]
780 fn closest_prefix_with_unitandabove() {
781 let constraint = Constraint::UnitAndAbove;
782
783 let exponent = -24;
784 let actual = Value::closest_prefix_for(exponent, &constraint);
785 let expected = Prefix::Unit;
786 assert_eq!(actual, expected);
787
788 let exponent = 0;
789 let actual = Value::closest_prefix_for(exponent, &constraint);
790 let expected = Prefix::Unit;
791 assert_eq!(actual, expected);
792
793 let exponent = 24;
794 let actual = Value::closest_prefix_for(exponent, &constraint);
795 let expected = Prefix::Yotta;
796 assert_eq!(actual, expected);
797
798 let exponent = 30;
799 let actual = Value::closest_prefix_for(exponent, &constraint);
800 let expected = Prefix::Yotta;
801 assert_eq!(actual, expected);
802
803 let exponent = 1; let actual = Value::closest_prefix_for(exponent, &constraint);
805 let expected = Prefix::Unit;
806 assert_eq!(actual, expected);
807 }
808
809 #[test]
813 fn closest_prefix_with_unitandbelow() {
814 let constraint = Constraint::UnitAndBelow;
815
816 let exponent = -24;
817 let actual = Value::closest_prefix_for(exponent, &constraint);
818 let expected = Prefix::Yocto;
819 assert_eq!(actual, expected);
820
821 let exponent = 0;
822 let actual = Value::closest_prefix_for(exponent, &constraint);
823 let expected = Prefix::Unit;
824 assert_eq!(actual, expected);
825
826 let exponent = 24;
827 let actual = Value::closest_prefix_for(exponent, &constraint);
828 let expected = Prefix::Unit;
829 assert_eq!(actual, expected);
830
831 let exponent = -30;
832 let actual = Value::closest_prefix_for(exponent, &constraint);
833 let expected = Prefix::Yocto;
834 assert_eq!(actual, expected);
835
836 let exponent = -1; let actual = Value::closest_prefix_for(exponent, &constraint);
838 let expected = Prefix::Unit;
839 assert_eq!(actual, expected);
840 }
841
842 #[test]
845 fn closest_prefix_with_custom() {
846 let constraint = Constraint::Custom(vec![Prefix::Milli, Prefix::Unit, Prefix::Kilo]);
847
848 let exponent = -24;
849 let actual = Value::closest_prefix_for(exponent, &constraint);
850 let expected = Prefix::Milli;
851 assert_eq!(actual, expected);
852
853 let exponent = -3;
854 let actual = Value::closest_prefix_for(exponent, &constraint);
855 let expected = Prefix::Milli;
856 assert_eq!(actual, expected);
857
858 let exponent = 0;
859 let actual = Value::closest_prefix_for(exponent, &constraint);
860 let expected = Prefix::Unit;
861 assert_eq!(actual, expected);
862
863 let exponent = 3;
864 let actual = Value::closest_prefix_for(exponent, &constraint);
865 let expected = Prefix::Kilo;
866 assert_eq!(actual, expected);
867
868 let exponent = 24;
869 let actual = Value::closest_prefix_for(exponent, &constraint);
870 let expected = Prefix::Kilo;
871 assert_eq!(actual, expected);
872
873 let exponent = -30;
874 let actual = Value::closest_prefix_for(exponent, &constraint);
875 let expected = Prefix::Milli;
876 assert_eq!(actual, expected);
877
878 let exponent = -1; let actual = Value::closest_prefix_for(exponent, &constraint);
880 let expected = Prefix::Milli;
881 assert_eq!(actual, expected);
882 }
883
884 #[test]
885 #[should_panic]
886 fn closest_prefix_with_custom_empty() {
887 let constraint = Constraint::Custom(vec![]);
888
889 let exponent = 3;
890 Value::closest_prefix_for(exponent, constraint);
891 }
892}