1pub extern crate muldiv;
68pub extern crate num_traits;
69pub extern crate typenum;
70
71pub mod aliases;
72pub mod fix_value;
73pub mod prelude;
74pub mod util;
75
76use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
77use core::fmt::{Debug, Display, Error, Formatter};
78use core::hash::{Hash, Hasher};
79use core::marker::PhantomData;
80use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
81use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
82
83use muldiv::MulDiv;
84use num_traits::{
85 CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, ConstZero, SaturatingAdd, SaturatingSub,
86};
87use paste::paste;
88use typenum::consts::{U10, Z0};
89use typenum::marker_traits::{Bit, Integer, Unsigned};
90use typenum::operator_aliases::{AbsVal, Diff, Le, Sum};
91use typenum::type_operators::{Abs, IsLess};
92
93pub struct Fix<Bits, Base, Exp> {
121 pub bits: Bits,
123
124 marker: PhantomData<(Base, Exp)>,
125}
126
127impl<Bits, Base, Exp> Fix<Bits, Base, Exp> {
128 pub fn new(bits: Bits) -> Self {
138 Fix {
139 bits,
140 marker: PhantomData,
141 }
142 }
143
144 pub const fn constant(bits: Bits) -> Self {
146 Fix {
147 bits,
148 marker: PhantomData,
149 }
150 }
151
152 pub fn convert<ToExp>(self) -> Fix<Bits, Base, ToExp>
164 where
165 Bits: FromUnsigned + Pow + Mul<Output = Bits> + Div<Output = Bits>,
166 Base: Unsigned,
167 Exp: Sub<ToExp>,
168 Diff<Exp, ToExp>: Abs + IsLess<Z0>,
169 AbsVal<Diff<Exp, ToExp>>: Integer,
170 {
171 let base = Bits::from_unsigned::<Base>();
172 let diff = AbsVal::<Diff<Exp, ToExp>>::to_i32();
173 let inverse = Le::<Diff<Exp, ToExp>, Z0>::to_bool();
174
175 let ratio = base.pow(diff.unsigned_abs());
178
179 if inverse {
180 Fix::new(self.bits / ratio)
181 } else {
182 Fix::new(self.bits * ratio)
183 }
184 }
185
186 pub fn widen<ToBits>(self) -> Fix<ToBits, Base, Exp>
198 where
199 ToBits: From<Bits>,
200 {
201 Fix::<ToBits, Base, Exp>::new(self.bits.into())
202 }
203
204 pub fn narrow<ToBits>(self) -> Option<Fix<ToBits, Base, Exp>>
217 where
218 ToBits: TryFrom<Bits>,
219 {
220 self.bits.try_into().ok().map(Fix::<ToBits, Base, Exp>::new)
221 }
222}
223
224pub trait FromUnsigned {
231 fn from_unsigned<U>() -> Self
233 where
234 U: Unsigned;
235}
236
237macro_rules! impl_from_unsigned {
238 ($ty:ident) => {
239 impl FromUnsigned for $ty {
240 fn from_unsigned<U: Unsigned>() -> Self {
241 paste! { U::[<to_$ty>]() }
242 }
243 }
244 };
245}
246
247impl_from_unsigned!(u8);
248impl_from_unsigned!(u16);
249impl_from_unsigned!(u32);
250impl_from_unsigned!(u64);
251impl_from_unsigned!(u128);
252impl_from_unsigned!(usize);
253impl_from_unsigned!(i8);
254impl_from_unsigned!(i16);
255impl_from_unsigned!(i32);
256impl_from_unsigned!(i64);
257impl_from_unsigned!(i128);
258impl_from_unsigned!(isize);
259
260pub trait Pow {
265 #[must_use]
267 fn pow(self, exp: u32) -> Self;
268}
269
270macro_rules! impl_pow {
271 ($ty:ident) => {
272 impl Pow for $ty {
273 #[inline]
274 fn pow(self, exp: u32) -> Self {
275 self.pow(exp)
276 }
277 }
278 };
279}
280
281impl_pow!(u8);
282impl_pow!(u16);
283impl_pow!(u32);
284impl_pow!(u64);
285impl_pow!(u128);
286impl_pow!(usize);
287impl_pow!(i8);
288impl_pow!(i16);
289impl_pow!(i32);
290impl_pow!(i64);
291impl_pow!(i128);
292impl_pow!(isize);
293
294impl<Bits, Base, Exp> Copy for Fix<Bits, Base, Exp> where Bits: Copy {}
297
298impl<Bits, Base, Exp> Clone for Fix<Bits, Base, Exp>
299where
300 Bits: Clone,
301{
302 fn clone(&self) -> Self {
303 Self::new(self.bits.clone())
304 }
305}
306
307impl<Bits, Base, Exp> Default for Fix<Bits, Base, Exp>
308where
309 Bits: Default,
310{
311 fn default() -> Self {
312 Self::new(Bits::default())
313 }
314}
315
316impl<Bits, Base, Exp> Fix<Bits, Base, Exp>
317where
318 Bits: ConstZero,
319{
320 #[must_use]
321 pub const fn zero() -> Self {
322 Self::constant(Bits::ZERO)
323 }
324}
325
326impl<Bits, Base, Exp> Hash for Fix<Bits, Base, Exp>
327where
328 Bits: Hash,
329{
330 fn hash<H>(&self, state: &mut H)
331 where
332 H: Hasher,
333 {
334 self.bits.hash(state);
335 }
336}
337
338impl<Bits, Base, Exp> Debug for Fix<Bits, Base, Exp>
339where
340 Bits: Debug,
341 Base: Unsigned,
342 Exp: Integer,
343{
344 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
345 write!(f, "{:?}x{}^{}", self.bits, Base::to_u64(), Exp::to_i64())
346 }
347}
348
349impl<Bits, Exp> Display for Fix<Bits, U10, Exp>
350where
351 Bits: Display,
352 Exp: Integer,
353{
354 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
355 let exp = Exp::to_i32();
356 let decimals = usize::try_from(exp.unsigned_abs()).map_err(|_| Error)?;
357 let raw = self.bits.to_string();
358 let (sign, digits) = raw
359 .strip_prefix('-')
360 .map_or(("", raw.as_str()), |d| ("-", d));
361
362 match exp {
363 0.. => write!(f, "{sign}{digits}{}", "0".repeat(decimals)),
364 _ if digits.len() > decimals => {
365 let (integer, fraction) = digits.split_at(digits.len() - decimals);
366 write!(f, "{sign}{integer}.{fraction}")
367 }
368 _ => {
369 let padding = "0".repeat(decimals - digits.len());
370 write!(f, "{sign}0.{padding}{digits}")
371 }
372 }
373 }
374}
375
376impl<Bits, Base, Exp> Eq for Fix<Bits, Base, Exp> where Bits: Eq {}
379impl<Bits, Base, Exp> PartialEq for Fix<Bits, Base, Exp>
380where
381 Bits: PartialEq,
382{
383 fn eq(&self, rhs: &Self) -> bool {
384 self.bits == rhs.bits
385 }
386}
387
388impl<Bits, Base, Exp> PartialOrd for Fix<Bits, Base, Exp>
389where
390 Bits: PartialOrd,
391{
392 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
393 self.bits.partial_cmp(&rhs.bits)
394 }
395}
396
397impl<Bits, Base, Exp> Ord for Fix<Bits, Base, Exp>
398where
399 Bits: Ord,
400{
401 fn cmp(&self, rhs: &Self) -> Ordering {
402 self.bits.cmp(&rhs.bits)
403 }
404}
405
406impl<Bits, Base, Exp> Neg for Fix<Bits, Base, Exp>
409where
410 Bits: Neg<Output = Bits>,
411{
412 type Output = Self;
413 fn neg(self) -> Self {
414 Self::new(-self.bits)
415 }
416}
417
418impl<Bits, Base, Exp> Add for Fix<Bits, Base, Exp>
419where
420 Bits: Add<Output = Bits>,
421{
422 type Output = Self;
423 fn add(self, rhs: Self) -> Self {
424 Self::new(self.bits + rhs.bits)
425 }
426}
427
428impl<Bits, Base, Exp> Sub for Fix<Bits, Base, Exp>
429where
430 Bits: Sub<Output = Bits>,
431{
432 type Output = Self;
433 fn sub(self, rhs: Self) -> Self {
434 Self::new(self.bits - rhs.bits)
435 }
436}
437
438impl<Bits, Base, LExp, RExp> Mul<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
439where
440 Bits: Mul<Output = Bits>,
441 LExp: Add<RExp>,
442{
443 type Output = Fix<Bits, Base, Sum<LExp, RExp>>;
444 fn mul(self, rhs: Fix<Bits, Base, RExp>) -> Self::Output {
445 Self::Output::new(self.bits * rhs.bits)
446 }
447}
448
449impl<Bits, Base, LExp, RExp> Div<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
450where
451 Bits: Div<Output = Bits>,
452 LExp: Sub<RExp>,
453{
454 type Output = Fix<Bits, Base, Diff<LExp, RExp>>;
455 fn div(self, rhs: Fix<Bits, Base, RExp>) -> Self::Output {
456 Self::Output::new(self.bits / rhs.bits)
457 }
458}
459
460impl<Bits, Base, Exp> Rem for Fix<Bits, Base, Exp>
461where
462 Bits: Rem<Output = Bits>,
463{
464 type Output = Self;
465 fn rem(self, rhs: Self) -> Self {
466 Self::new(self.bits % rhs.bits)
467 }
468}
469
470impl<Bits, Base, Exp> Mul<Bits> for Fix<Bits, Base, Exp>
471where
472 Bits: Mul<Output = Bits>,
473{
474 type Output = Self;
475 fn mul(self, rhs: Bits) -> Self {
476 Self::new(self.bits * rhs)
477 }
478}
479
480impl<Bits, Base, Exp> Div<Bits> for Fix<Bits, Base, Exp>
481where
482 Bits: Div<Output = Bits>,
483{
484 type Output = Self;
485 fn div(self, rhs: Bits) -> Self {
486 Self::new(self.bits / rhs)
487 }
488}
489
490impl<Bits, Base, Exp> Rem<Bits> for Fix<Bits, Base, Exp>
491where
492 Bits: Rem<Output = Bits>,
493{
494 type Output = Self;
495 fn rem(self, rhs: Bits) -> Self {
496 Self::new(self.bits % rhs)
497 }
498}
499
500impl<Bits, Base, Exp> AddAssign for Fix<Bits, Base, Exp>
501where
502 Bits: AddAssign,
503{
504 fn add_assign(&mut self, rhs: Self) {
505 self.bits += rhs.bits;
506 }
507}
508
509impl<Bits, Base, Exp> SubAssign for Fix<Bits, Base, Exp>
510where
511 Bits: SubAssign,
512{
513 fn sub_assign(&mut self, rhs: Self) {
514 self.bits -= rhs.bits;
515 }
516}
517
518impl<Bits, Base, Exp> MulAssign<Bits> for Fix<Bits, Base, Exp>
519where
520 Bits: MulAssign,
521{
522 fn mul_assign(&mut self, rhs: Bits) {
523 self.bits *= rhs;
524 }
525}
526
527impl<Bits, Base, Exp> DivAssign<Bits> for Fix<Bits, Base, Exp>
528where
529 Bits: DivAssign,
530{
531 fn div_assign(&mut self, rhs: Bits) {
532 self.bits /= rhs;
533 }
534}
535
536impl<Bits, Base, LExp, RExp> RemAssign<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
537where
538 Bits: RemAssign,
539{
540 fn rem_assign(&mut self, rhs: Fix<Bits, Base, RExp>) {
541 self.bits %= rhs.bits;
542 }
543}
544
545impl<Bits, Base, Exp> RemAssign<Bits> for Fix<Bits, Base, Exp>
546where
547 Bits: RemAssign,
548{
549 fn rem_assign(&mut self, rhs: Bits) {
550 self.bits %= rhs;
551 }
552}
553
554impl<Bits, Base, Exp> CheckedAdd for Fix<Bits, Base, Exp>
557where
558 Bits: CheckedAdd,
559{
560 fn checked_add(&self, v: &Self) -> Option<Self> {
561 self.bits.checked_add(&v.bits).map(Self::new)
562 }
563}
564
565impl<Bits, Base, Exp> CheckedSub for Fix<Bits, Base, Exp>
566where
567 Bits: CheckedSub,
568{
569 fn checked_sub(&self, v: &Self) -> Option<Self> {
570 self.bits.checked_sub(&v.bits).map(Self::new)
571 }
572}
573
574impl<Bits, Base, Exp> Fix<Bits, Base, Exp>
575where
576 Self: CheckedSub,
577 Bits: Copy,
578{
579 #[must_use]
580 pub fn abs_diff(&self, v: &Self) -> Fix<Bits, Base, Exp> {
581 self.checked_sub(v).unwrap_or_else(|| *v - *self)
582 }
583}
584
585pub trait CheckedMulFix<Rhs> {
587 type Output;
588 fn checked_mul(&self, v: &Rhs) -> Option<Self::Output>;
589}
590
591impl<Bits, Base, LExp, RExp> CheckedMulFix<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
592where
593 Bits: CheckedMul,
594 LExp: Add<RExp>,
595{
596 type Output = Fix<Bits, Base, Sum<LExp, RExp>>;
597 fn checked_mul(&self, v: &Fix<Bits, Base, RExp>) -> Option<Self::Output> {
598 self.bits.checked_mul(&v.bits).map(Self::Output::new)
599 }
600}
601
602pub trait CheckedDivFix<Rhs> {
604 type Output;
605 fn checked_div(&self, v: &Rhs) -> Option<Self::Output>;
606}
607
608impl<Bits, Base, LExp, RExp> CheckedDivFix<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
609where
610 Bits: CheckedDiv,
611 LExp: Sub<RExp>,
612{
613 type Output = Fix<Bits, Base, Diff<LExp, RExp>>;
614 fn checked_div(&self, v: &Fix<Bits, Base, RExp>) -> Option<Self::Output> {
615 self.bits.checked_div(&v.bits).map(Self::Output::new)
616 }
617}
618
619impl<Bits, Base, LExp, RExp> MulDiv<Fix<Bits, Base, RExp>> for Fix<Bits, Base, LExp>
620where
621 Bits: MulDiv,
622{
623 type Output = Fix<<Bits as MulDiv>::Output, Base, LExp>;
624 fn mul_div_ceil(
625 self,
626 num: Fix<Bits, Base, RExp>,
627 denom: Fix<Bits, Base, RExp>,
628 ) -> Option<Self::Output> {
629 self.bits
630 .mul_div_ceil(num.bits, denom.bits)
631 .map(Self::Output::new)
632 }
633 fn mul_div_floor(
634 self,
635 num: Fix<Bits, Base, RExp>,
636 denom: Fix<Bits, Base, RExp>,
637 ) -> Option<Self::Output> {
638 self.bits
639 .mul_div_floor(num.bits, denom.bits)
640 .map(Self::Output::new)
641 }
642 fn mul_div_round(
643 self,
644 num: Fix<Bits, Base, RExp>,
645 denom: Fix<Bits, Base, RExp>,
646 ) -> Option<Self::Output> {
647 self.bits
648 .mul_div_round(num.bits, denom.bits)
649 .map(Self::Output::new)
650 }
651}
652
653impl<Bits, Base, Exp> SaturatingAdd for Fix<Bits, Base, Exp>
656where
657 Bits: SaturatingAdd,
658{
659 fn saturating_add(&self, v: &Self) -> Self {
660 Self::new(self.bits.saturating_add(&v.bits))
661 }
662}
663
664impl<Bits, Base, Exp> SaturatingSub for Fix<Bits, Base, Exp>
665where
666 Bits: SaturatingSub,
667{
668 fn saturating_sub(&self, v: &Self) -> Self {
669 Self::new(self.bits.saturating_sub(&v.bits))
670 }
671}
672
673#[cfg(test)]
674mod tests {
675 use num_traits::{SaturatingAdd, SaturatingSub};
676 use typenum::{N3, P3, Z0};
677
678 use crate::aliases::decimal::{IFix64, UFix64};
679 use crate::aliases::si::{Kilo, Micro, Milli, Nano, Unit};
680 use crate::{CheckedAdd, CheckedDivFix, CheckedMulFix, CheckedSub, MulDiv};
681
682 #[test]
683 fn convert_milli_to_kilo() {
684 assert_eq!(Kilo::new(15), Milli::new(15_000_000).convert());
685 }
686
687 #[test]
688 fn convert_kilo_to_milli() {
689 assert_eq!(Milli::new(15_000_000), Kilo::new(15).convert());
690 }
691
692 #[test]
693 fn cmp() {
694 assert!(Kilo::new(1) < Kilo::new(2));
695 }
696
697 #[test]
698 fn neg() {
699 assert_eq!(Kilo::new(-1), -Kilo::new(1i32));
700 }
701
702 #[test]
703 fn add() {
704 assert_eq!(Kilo::new(3), Kilo::new(1) + Kilo::new(2));
705 }
706
707 #[test]
708 fn sub() {
709 assert_eq!(Kilo::new(1), Kilo::new(3) - Kilo::new(2));
710 }
711
712 #[test]
713 fn mul() {
714 assert_eq!(Unit::new(6), Kilo::new(2) * Milli::new(3));
715 }
716
717 #[test]
718 fn div() {
719 assert_eq!(Unit::new(3), Kilo::new(6) / Kilo::new(2));
720 }
721
722 #[test]
723 fn rem() {
724 assert_eq!(Kilo::new(1), Kilo::new(6) % Kilo::new(5));
725 }
726
727 #[test]
728 fn mul_bits() {
729 assert_eq!(Kilo::new(6), Kilo::new(2) * 3);
730 }
731
732 #[test]
733 fn div_bits() {
734 assert_eq!(Kilo::new(3), Kilo::new(6) / 2);
735 }
736
737 #[test]
738 fn rem_bits() {
739 assert_eq!(Kilo::new(1), Kilo::new(6) % 5);
740 }
741
742 #[test]
743 fn add_assign() {
744 let mut a = Kilo::new(1);
745 a += Kilo::new(2);
746 assert_eq!(Kilo::new(3), a);
747 }
748
749 #[test]
750 fn sub_assign() {
751 let mut a = Kilo::new(3);
752 a -= Kilo::new(2);
753 assert_eq!(Kilo::new(1), a);
754 }
755
756 #[test]
757 fn mul_assign_bits() {
758 let mut a = Kilo::new(2);
759 a *= 3;
760 assert_eq!(Kilo::new(6), a);
761 }
762
763 #[test]
764 fn div_assign_bits() {
765 let mut a = Kilo::new(6);
766 a /= 2;
767 assert_eq!(Kilo::new(3), a);
768 }
769
770 #[test]
771 fn rem_assign() {
772 let mut a = Kilo::new(6);
773 a %= Milli::new(5);
774 assert_eq!(Kilo::new(1), a);
775 }
776
777 #[test]
778 fn rem_assign_bits() {
779 let mut a = Kilo::new(6);
780 a %= 5;
781 assert_eq!(Kilo::new(1), a);
782 }
783
784 #[test]
785 fn checked_add_neg() {
786 let max = Kilo::new(u8::MAX);
787 let one = Kilo::new(1);
788 assert!(max.checked_add(&one).is_none());
789 }
790
791 #[test]
792 fn checked_add_pos() {
793 let forty = Kilo::new(40);
794 let two = Kilo::new(2);
795 assert_eq!(forty.checked_add(&two), Some(Kilo::new(42)));
796 }
797
798 #[test]
799 fn checked_sub_neg() {
800 let one = Kilo::new(1);
801 let max = Kilo::new(u8::MAX);
802 assert!(one.checked_sub(&max).is_none());
803 }
804
805 #[test]
806 fn checked_sub_pos() {
807 let fifty = Kilo::new(50);
808 let eight = Kilo::new(8);
809 assert_eq!(fifty.checked_sub(&eight), Some(Kilo::new(42)));
810 }
811
812 #[test]
813 fn checked_mul_neg() {
814 let fifty = Kilo::new(50);
815 let max = Kilo::new(u8::MAX);
816 assert!(fifty.checked_mul(&max).is_none());
817 }
818
819 #[test]
820 fn checked_mul_pos() {
821 let fifty = Kilo::new(50_u64);
822 assert_eq!(
823 fifty.checked_mul(&fifty).map(super::Fix::convert),
824 Some(Kilo::new(2_500_000_u64))
825 );
826 }
827
828 #[test]
829 fn checked_div_neg() {
830 let one = Unit::new(0);
831 assert!(one.checked_div(&one).is_none());
832 }
833
834 #[test]
835 fn checked_div_pos() {
836 let hundred = Kilo::new(100);
837 let five = Kilo::new(5);
838 assert_eq!(hundred.checked_div(&five), Some(Unit::new(20)));
839 }
840
841 #[test]
842 fn narrow_succeeds() {
843 let one = Milli::new(1000u128);
844 let mapped = one.narrow::<u64>();
845 assert_eq!(mapped, Some(Milli::new(1000u64)));
846 }
847
848 #[test]
849 fn narrow_fails() {
850 let one = Milli::new(1699u64);
851 let mapped = one.narrow::<u8>();
852 assert_eq!(mapped, None);
853 }
854
855 #[test]
856 fn widen_succeeds() {
857 let one = Milli::new(1_340_191u64);
858 let mapped = one.widen::<u128>();
859 assert_eq!(mapped, Milli::new(1_340_191_u128));
860 }
861
862 #[test]
863 fn mul_div_ceil() {
864 let start = Milli::new(313_459u64);
865 let mul = Milli::new(1200u64);
866 let div = Milli::new(2450u64);
867 assert_eq!(start.mul_div_ceil(mul, div), Some(Milli::new(153_531)));
868 }
869
870 #[test]
871 fn mul_div_ceil_unit() {
872 let start = Milli::new(31_345_934u64);
873 let mul = Milli::new(1000u64);
874 let div = Milli::new(2000u64);
875 assert_eq!(
876 start.mul_div_ceil(mul, div),
877 Some(Milli::new(15_672_967_u64))
878 );
879 }
880
881 #[test]
882 fn mul_div_floor() {
883 let start = Milli::new(69_693u64);
884 let mul = Milli::new(5_192u64);
885 let div = Milli::new(190u64);
886 assert_eq!(
887 start.mul_div_floor(mul, div),
888 Some(Milli::new(1_904_452_u64))
889 );
890 }
891
892 #[test]
893 fn mul_div_floor_unit() {
894 let start = Milli::new(69_693u64);
895 let mul = Milli::new(1000u64);
896 let div = Milli::new(9u64);
897 assert_eq!(
898 start.mul_div_floor(mul, div),
899 Some(Milli::new(7_743_666_u64))
900 );
901 }
902
903 #[test]
904 fn mul_div_round() {
905 let start = Milli::new(1892u64);
906 let mul = Milli::new(3222u64);
907 let div = Milli::new(9999u64);
908 assert_eq!(start.mul_div_round(mul, div), Some(Milli::new(610u64)));
909 }
910
911 #[test]
912 fn mul_div_round_unit() {
913 let start = Milli::new(1892u64);
914 let mul = Milli::new(1000u64);
915 let div = Milli::new(322u64);
916 assert_eq!(start.mul_div_round(mul, div), Some(Milli::new(5876u64)));
917 }
918
919 #[test]
920 fn abs_diff() {
921 let start = Milli::new(u128::MIN);
922 let end = Milli::new(u128::MAX);
923 assert_eq!(start.abs_diff(&end), end);
924 }
925
926 #[test]
927 fn constant() {
928 assert_eq!(Kilo::constant(69u64), Kilo::new(69u64));
929 }
930
931 #[test]
932 fn saturating_sub() {
933 let zero = Kilo::constant(0);
934 let result = zero.saturating_sub(&Kilo::new(69u64));
935 assert_eq!(zero, result);
936 }
937
938 #[test]
939 fn saturating_add() {
940 let max = Kilo::new(u64::MAX);
941 let result = max.saturating_add(&Kilo::new(69u64));
942 assert_eq!(max, result);
943 }
944
945 #[test]
946 fn zero_is_zero() {
947 assert_eq!(Kilo::<u64>::zero().bits, 0);
948 assert_eq!(Milli::<u64>::zero().bits, 0);
949 assert_eq!(Nano::<u64>::zero().bits, 0);
950 }
951
952 #[test]
953 fn one_is_correct() {
954 assert_eq!(Milli::<u64>::one().bits, 1_000);
955 assert_eq!(Micro::<u64>::one().bits, 1_000_000);
956 assert_eq!(Nano::<u64>::one().bits, 1_000_000_000);
957 }
958
959 #[test]
960 fn checked_convert_upconvert() {
961 assert_eq!(
962 Milli::new(5u64).checked_convert(),
963 Some(Micro::new(5_000u64)),
964 );
965 }
966
967 #[test]
968 fn checked_convert_downconvert() {
969 assert_eq!(
970 Micro::new(5_000u64).checked_convert(),
971 Some(Milli::new(5u64)),
972 );
973 }
974
975 #[test]
976 fn checked_convert_identity() {
977 assert_eq!(Milli::new(42u64).checked_convert(), Some(Milli::new(42u64)),);
978 }
979
980 #[test]
981 fn checked_convert_overflow() {
982 assert_eq!(Milli::new(u64::MAX).checked_convert::<typenum::N9>(), None,);
983 }
984
985 #[test]
986 fn checked_convert_matches_convert() {
987 let value = Milli::new(15u64);
988 assert_eq!(
989 value.checked_convert::<typenum::N6>(),
990 Some(value.convert::<typenum::N6>()),
991 );
992 }
993
994 #[test]
995 fn display_negative_exp() {
996 assert_eq!(UFix64::<N3>::new(1_234).to_string(), "1.234");
997 assert_eq!(UFix64::<N3>::new(1).to_string(), "0.001");
998 assert_eq!(UFix64::<N3>::new(0).to_string(), "0.000");
999 }
1000
1001 #[test]
1002 fn display_negative_exp_signed() {
1003 assert_eq!(IFix64::<N3>::new(-1_234).to_string(), "-1.234");
1004 assert_eq!(IFix64::<N3>::new(-1).to_string(), "-0.001");
1005 }
1006
1007 #[test]
1008 fn display_positive_exp() {
1009 assert_eq!(UFix64::<P3>::new(5).to_string(), "5000");
1010 }
1011
1012 #[test]
1013 fn display_zero_exp() {
1014 assert_eq!(UFix64::<Z0>::new(42).to_string(), "42");
1015 }
1016}