Skip to main content

repose_kinematics/
serde_arrays.rs

1//! Serde helpers for const-generic fixed-size arrays.
2//!
3//! This is the one shared set of fixed-array serde helpers for the workspace. Use a module with
4//! `#[serde(with = "repose_kinematics::serde_arrays::<module>")]` on a `[T; N]` field; each module
5//! provides `serialize` and `deserialize`, encodes the array as a tuple of exactly `N` elements,
6//! and rejects sequences of any other length.
7//!
8//! ```rust
9//! use repose_kinematics::CuJointPosition;
10//! use serde::{Deserialize, Serialize};
11//!
12//! #[derive(Serialize, Deserialize)]
13//! struct Goal<const N: usize> {
14//!     #[serde(with = "repose_kinematics::serde_arrays::position_array")]
15//!     positions: [CuJointPosition; N],
16//! }
17//! ```
18
19macro_rules! impl_const_array_serde {
20    ($mod_name:ident, $elem_ty:ty, $label:literal) => {
21        #[doc = concat!("Serde `with` module for `[", $label, "; N]` arrays.")]
22        pub mod $mod_name {
23            use serde::Deserializer;
24            use serde::Serializer;
25            use serde::de::Error as DeError;
26            use serde::de::SeqAccess;
27            use serde::de::Visitor;
28            use serde::ser::SerializeTuple;
29
30            /// Serializes the array as an `N`-element tuple.
31            pub fn serialize<S, const N: usize>(
32                values: &[$elem_ty; N],
33                serializer: S,
34            ) -> Result<S::Ok, S::Error>
35            where
36                S: Serializer,
37            {
38                let mut seq = serializer.serialize_tuple(N)?;
39                let mut i = 0;
40                while i < N {
41                    seq.serialize_element(&values[i])?;
42                    i += 1;
43                }
44                seq.end()
45            }
46
47            /// Deserializes exactly `N` elements, rejecting shorter or longer sequences.
48            pub fn deserialize<'de, D, const N: usize>(
49                deserializer: D,
50            ) -> Result<[$elem_ty; N], D::Error>
51            where
52                D: Deserializer<'de>,
53            {
54                struct ArrayVisitor<const M: usize>;
55
56                impl<'de, const M: usize> Visitor<'de> for ArrayVisitor<M> {
57                    type Value = [$elem_ty; M];
58
59                    fn expecting(
60                        &self,
61                        formatter: &mut core::fmt::Formatter<'_>,
62                    ) -> core::fmt::Result {
63                        write!(formatter, "an array of {M} {} values", $label)
64                    }
65
66                    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
67                    where
68                        A: SeqAccess<'de>,
69                    {
70                        let mut out = [<$elem_ty>::default(); M];
71                        let mut i = 0;
72                        while i < M {
73                            out[i] = seq
74                                .next_element()?
75                                .ok_or_else(|| DeError::invalid_length(i, &self))?;
76                            i += 1;
77                        }
78                        if seq.next_element::<serde::de::IgnoredAny>()?.is_some() {
79                            return Err(DeError::invalid_length(M + 1, &self));
80                        }
81                        Ok(out)
82                    }
83                }
84
85                deserializer.deserialize_tuple(N, ArrayVisitor::<N>)
86            }
87        }
88    };
89}
90
91impl_const_array_serde!(joint_spec_array, crate::chain::CuJointSpec, "CuJointSpec");
92impl_const_array_serde!(angle_array, cu29::units::si::f64::Angle, "Angle64");
93impl_const_array_serde!(
94    angular_velocity_array,
95    cu29::units::si::f64::AngularVelocity,
96    "AngularVelocity64"
97);
98
99impl_const_array_serde!(
100    position_array,
101    crate::joint::CuJointPosition,
102    "CuJointPosition"
103);
104impl_const_array_serde!(
105    velocity_array,
106    crate::joint::CuJointVelocity,
107    "CuJointVelocity"
108);
109impl_const_array_serde!(
110    acceleration_array,
111    crate::joint::CuJointAcceleration,
112    "CuJointAcceleration"
113);
114impl_const_array_serde!(jerk_array, crate::joint::CuJointJerk, "CuJointJerk");