Skip to main content

dsp_fixedpoint/
serde.rs

1//! Serde adapters for fixed-point wire formats.
2//!
3//! The direct `Q` serde implementation is transparent and uses the raw
4//! representation. Use [`as_f32`] or [`as_f64`] when the wire format should
5//! carry the scaled value through serde's floating-point data model instead.
6
7use ::serde::{Deserialize, Deserializer, Serializer};
8use num_traits::{AsPrimitive, ToPrimitive};
9
10use crate::Q;
11
12/// Serialize and lossy-deserialize `Q` through serde's `f32` data model.
13///
14/// This maps `Q::<i32, i64, 3>::from_bits(1)` to the JSON number `0.125` and back.
15pub mod as_f32 {
16    use super::*;
17
18    /// Serialize as a scaled `f32` value.
19    pub fn serialize<S, T, A, const F: i8>(q: &Q<T, A, F>, serializer: S) -> Result<S::Ok, S::Error>
20    where
21        S: Serializer,
22        Q<T, A, F>: ToPrimitive,
23    {
24        serializer.serialize_f32(
25            q.to_f32()
26                .ok_or_else(|| ::serde::ser::Error::custom("fixed-point value is not finite"))?,
27        )
28    }
29
30    /// Deserialize from a scaled `f32` value.
31    pub fn deserialize<'de, D, T, A, const F: i8>(deserializer: D) -> Result<Q<T, A, F>, D::Error>
32    where
33        D: Deserializer<'de>,
34        f32: AsPrimitive<Q<T, A, F>>,
35        Q<T, A, F>: Copy + 'static,
36    {
37        f32::deserialize(deserializer).map(Q::from_f32)
38    }
39}
40
41/// Serialize and lossy-deserialize `Q` through serde's `f64` data model.
42///
43/// This maps `Q::<i32, i64, 3>::from_bits(1)` to the JSON number `0.125` and back.
44pub mod as_f64 {
45    use super::*;
46
47    /// Serialize as a scaled `f64` value.
48    pub fn serialize<S, T, A, const F: i8>(q: &Q<T, A, F>, serializer: S) -> Result<S::Ok, S::Error>
49    where
50        S: Serializer,
51        Q<T, A, F>: ToPrimitive,
52    {
53        serializer.serialize_f64(
54            q.to_f64()
55                .ok_or_else(|| ::serde::ser::Error::custom("fixed-point value is not finite"))?,
56        )
57    }
58
59    /// Deserialize from a scaled `f64` value.
60    pub fn deserialize<'de, D, T, A, const F: i8>(deserializer: D) -> Result<Q<T, A, F>, D::Error>
61    where
62        D: Deserializer<'de>,
63        f64: AsPrimitive<Q<T, A, F>>,
64        Q<T, A, F>: Copy + 'static,
65    {
66        f64::deserialize(deserializer).map(Q::from_f64)
67    }
68}
69
70#[cfg(test)]
71mod test {
72    use super::*;
73    use ::serde::{Deserialize, Serialize};
74
75    #[derive(Debug, Deserialize, PartialEq, Serialize)]
76    struct F32 {
77        #[serde(with = "as_f32")]
78        value: crate::Q<i32, i64, 3>,
79    }
80
81    #[derive(Debug, Deserialize, PartialEq, Serialize)]
82    struct F64 {
83        #[serde(with = "as_f64")]
84        value: crate::Q<i32, i64, 3>,
85    }
86
87    #[test]
88    fn as_f32_uses_scaled_value() {
89        let value = F32 {
90            value: crate::Q::new(1),
91        };
92        let mut out = [0; 32];
93        let len = serde_json_core::to_slice(&value, &mut out).unwrap();
94        let json = &out[..len];
95        assert_eq!(json, br#"{"value":0.125}"#);
96        assert_eq!(serde_json_core::from_slice::<F32>(json).unwrap().0, value);
97    }
98
99    #[test]
100    fn as_f64_uses_scaled_value() {
101        let value = F64 {
102            value: crate::Q::new(1),
103        };
104        let mut out = [0; 32];
105        let len = serde_json_core::to_slice(&value, &mut out).unwrap();
106        let json = &out[..len];
107        assert_eq!(json, br#"{"value":0.125}"#);
108        assert_eq!(serde_json_core::from_slice::<F64>(json).unwrap().0, value);
109    }
110}