messagepack_core/encode/
float.rs

1//! Floating‑point encoders.
2
3use super::{Encode, Result};
4use crate::{formats::Format, io::IoWrite};
5
6impl<W> Encode<W> for f32
7where
8    W: IoWrite,
9{
10    fn encode(&self, writer: &mut W) -> Result<usize, <W as IoWrite>::Error> {
11        writer.write(&Format::Float32.as_slice())?;
12        writer.write(&self.to_be_bytes())?;
13        Ok(5)
14    }
15}
16
17impl<W> Encode<W> for f64
18where
19    W: IoWrite,
20{
21    fn encode(&self, writer: &mut W) -> Result<usize, <W as IoWrite>::Error> {
22        writer.write(&Format::Float64.as_slice())?;
23        writer.write(&self.to_be_bytes())?;
24        Ok(9)
25    }
26}
27
28fn is_exactly_representable(x: f64) -> bool {
29    x.is_finite() && (x as f32) as f64 == x
30}
31
32/// encode minimum byte size
33#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
34pub enum EncodeMinimizeFloat {
35    /// Encode as `float32` if exact, otherwise upcast to `float64`.
36    F32(f32),
37    /// Always encode as `float64`.
38    F64(f64),
39}
40
41impl From<f32> for EncodeMinimizeFloat {
42    fn from(value: f32) -> Self {
43        EncodeMinimizeFloat::F32(value)
44    }
45}
46
47impl From<f64> for EncodeMinimizeFloat {
48    fn from(value: f64) -> Self {
49        EncodeMinimizeFloat::F64(value)
50    }
51}
52
53impl<W> Encode<W> for EncodeMinimizeFloat
54where
55    W: IoWrite,
56{
57    fn encode(&self, writer: &mut W) -> Result<usize, <W as IoWrite>::Error> {
58        {
59            match self {
60                EncodeMinimizeFloat::F32(v) => v.encode(writer),
61                EncodeMinimizeFloat::F64(v) => {
62                    let v = *v;
63                    if is_exactly_representable(v) {
64                        (v as f32).encode(writer)
65                    } else {
66                        v.encode(writer)
67                    }
68                }
69            }
70        }
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    use rstest::rstest;
79
80    #[rstest]
81    #[case(123.456_f32,[Format::Float32.as_byte(), 0x42, 0xf6, 0xe9, 0x79])]
82    fn encode_float32<V: Encode<Vec<u8>>, E: AsRef<[u8]> + Sized>(
83        #[case] value: V,
84        #[case] expected: E,
85    ) {
86        let expected = expected.as_ref();
87
88        let mut buf = vec![];
89        let n = value.encode(&mut buf).unwrap();
90        assert_eq!(buf, expected);
91        assert_eq!(n, expected.len());
92    }
93
94    #[rstest]
95    #[case(123456.789_f64,[Format::Float64.as_byte(), 0x40, 0xfe, 0x24, 0x0c, 0x9f, 0xbe, 0x76, 0xc9])]
96    fn encode_float64<V: Encode<Vec<u8>>, E: AsRef<[u8]> + Sized>(
97        #[case] value: V,
98        #[case] expected: E,
99    ) {
100        let expected = expected.as_ref();
101
102        let mut buf = vec![];
103        let n = value.encode(&mut buf).unwrap();
104        assert_eq!(buf, expected);
105        assert_eq!(n, expected.len());
106    }
107
108    #[rstest]
109    #[case(1.0_f64, [Format::Float32.as_byte(), 0x3f, 0x80, 0x00, 0x00])]
110    #[case(1e39_f64, [Format::Float64.as_byte(), 0x48,0x07,0x82,0x87,0xf4,0x9c,0x4a,0x1d])]
111    fn encode_float_minimize<V: Into<EncodeMinimizeFloat>, E: AsRef<[u8]> + Sized>(
112        #[case] value: V,
113        #[case] expected: E,
114    ) {
115        let expected = expected.as_ref();
116        let encoder = value.into();
117
118        let mut buf = vec![];
119        let n = encoder.encode(&mut buf).unwrap();
120        assert_eq!(buf, expected);
121        assert_eq!(n, expected.len());
122    }
123}