Skip to main content

messagepack_core/encode/
float.rs

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