1use crate::{
2 FpClassify, FpTruncate, PackedFloat, PackedFloatValidator, F16, F24, F32, F40, F48, F56, F64,
3 F8,
4};
5
6pub trait FpPack {
7 type Validator;
8
9 fn pack_native(self, validator: &Self::Validator) -> PackedFloat;
10 fn pack_optimal(self, validator: &Self::Validator) -> PackedFloat;
11}
12
13macro_rules! truncate_validated {
14 ($src:ty => $dst:ty, $native:expr, $validate:expr) => {{
15 let (native, validate) = ($native, $validate);
16
17 let non_packed_src: $src = native.into();
18 let (packed_src, packed_dst): ($src, $dst) = non_packed_src.truncate();
19
20 if (validate)(non_packed_src, packed_src) {
21 if packed_dst.classify() == packed_src.classify() {
22 Some(packed_dst)
23 } else {
24 None
25 }
26 } else {
27 None
28 }
29 }};
30}
31
32impl FpPack for F32 {
33 type Validator = PackedFloatValidator<f32>;
34
35 #[inline]
36 fn pack_native(self, validator: &Self::Validator) -> PackedFloat {
37 #[allow(unused_variables)]
38 let non_packed: f32 = self.into();
39
40 #[allow(unused_variables)]
41 let validate = |value: F32, packed: F32| {
42 let value: f32 = value.into();
43 let packed: f32 = packed.into();
44 validator.validate(value, packed)
45 };
46
47 PackedFloat::F32(self)
48 }
49
50 #[inline]
51 fn pack_optimal(self, validator: &Self::Validator) -> PackedFloat {
52 let non_packed: f32 = self.into();
53
54 let validate = |value: F32, packed: F32| {
55 let value: f32 = value.into();
56 let packed: f32 = packed.into();
57 validator.validate(value, packed)
58 };
59
60 if let Some(packed) = truncate_validated!(F32 => F16, non_packed, validate) {
61 if let Some(packed) = truncate_validated!(F32 => F8, non_packed, validate) {
62 PackedFloat::F8(packed)
63 } else {
64 PackedFloat::F16(packed)
65 }
66 } else {
67 #[allow(clippy::collapsible_else_if)]
68 if let Some(packed) = truncate_validated!(F32 => F24, non_packed, validate) {
69 PackedFloat::F24(packed)
70 } else {
71 PackedFloat::F32(self)
72 }
73 }
74 }
75}
76
77impl FpPack for F64 {
78 type Validator = PackedFloatValidator<f64>;
79
80 #[inline]
81 fn pack_native(self, validator: &Self::Validator) -> PackedFloat {
82 let non_packed: f64 = self.into();
83
84 let validate = |value: F64, packed: F64| {
85 let value: f64 = value.into();
86 let packed: f64 = packed.into();
87 validator.validate(value, packed)
88 };
89
90 if let Some(packed) = truncate_validated!(F64 => F32, non_packed, validate) {
91 PackedFloat::F32(packed)
92 } else {
93 PackedFloat::F64(self)
94 }
95 }
96
97 #[inline]
98 fn pack_optimal(self, validator: &Self::Validator) -> PackedFloat {
99 let non_packed: f64 = self.into();
100
101 let validate = |value: F64, packed: F64| {
102 let value: f64 = value.into();
103 let packed: f64 = packed.into();
104 validator.validate(value, packed)
105 };
106
107 if let Some(packed) = truncate_validated!(F64 => F32, non_packed, validate) {
108 if let Some(packed) = truncate_validated!(F64 => F16, non_packed, validate) {
109 if let Some(packed) = truncate_validated!(F64 => F8, non_packed, validate) {
110 PackedFloat::F8(packed)
111 } else {
112 PackedFloat::F16(packed)
113 }
114 } else if let Some(packed) = truncate_validated!(F64 => F24, non_packed, validate) {
115 PackedFloat::F24(packed)
116 } else {
117 PackedFloat::F32(packed)
118 }
119 } else if let Some(packed) = truncate_validated!(F64 => F48, non_packed, validate) {
120 if let Some(packed) = truncate_validated!(F64 => F40, non_packed, validate) {
121 PackedFloat::F40(packed)
122 } else {
123 PackedFloat::F48(packed)
124 }
125 } else if let Some(packed) = truncate_validated!(F64 => F56, non_packed, validate) {
126 PackedFloat::F56(packed)
127 } else {
128 PackedFloat::F64(self)
129 }
130 }
131}