lilliput_float/
pack.rs

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}