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