Skip to main content

mavlink/dialects/
dynamic_serde.rs

1//! Serialization support for runtime loaded MAVLink messages.
2
3use mavlink_bindgen::parser::MavType;
4use serde::{
5    Serialize, Serializer,
6    ser::{Error as _, SerializeMap, SerializeTuple},
7};
8
9use super::{
10    dynamic::{DynamicEnumDefinition, DynamicMessage},
11    dynamic_parser::{cast_integer, enum_value_fits},
12};
13
14impl Serialize for DynamicMessage {
15    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
16    where
17        S: Serializer,
18    {
19        let definition = self.definition();
20        let mut message = serializer.serialize_map(Some(definition.fields().len() + 1))?;
21        message.serialize_entry("type", definition.name())?;
22        for field in definition.fields() {
23            message.serialize_entry(
24                field.name(),
25                &SerializableField {
26                    mavtype: &field.mavtype,
27                    enumeration: field.enumeration.as_deref(),
28                    bytes: available_bytes(self.payload(), field.offset(), field.encoded_size()),
29                },
30            )?;
31        }
32        message.end()
33    }
34}
35
36struct SerializableField<'a> {
37    mavtype: &'a MavType,
38    enumeration: Option<&'a DynamicEnumDefinition>,
39    bytes: &'a [u8],
40}
41
42impl Serialize for SerializableField<'_> {
43    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
44    where
45        S: Serializer,
46    {
47        if let MavType::Array(element_type, length) = self.mavtype {
48            let element_size = element_type.size();
49            let mut sequence = serializer.serialize_tuple(*length)?;
50            for index in 0..*length {
51                let offset = index * element_size;
52                sequence.serialize_element(&Self {
53                    mavtype: element_type,
54                    enumeration: None,
55                    bytes: available_bytes(self.bytes, offset, element_size),
56                })?;
57            }
58            return sequence.end();
59        }
60
61        if let MavType::CharArray(length) = self.mavtype {
62            let length = (*length).min(self.bytes.len());
63            let bytes = &self.bytes[..length];
64            let bytes = &bytes[..bytes.iter().position(|byte| *byte == 0).unwrap_or(length)];
65            return serializer.serialize_str(std::str::from_utf8(bytes).map_err(S::Error::custom)?);
66        }
67
68        if let Some(enumeration) = self.enumeration {
69            let value = read_integer(self.mavtype, self.bytes).ok_or_else(|| {
70                S::Error::custom(format!(
71                    "enum {} must use an integer field type",
72                    enumeration.name
73                ))
74            })?;
75
76            if let Some(primitive) = &enumeration.primitive {
77                let value = cast_integer(primitive, value)
78                    .ok_or_else(|| S::Error::custom("bitmask must use an integer type"))?;
79                if serializer.is_human_readable() {
80                    let bits = value & (u64::MAX >> (64 - primitive.size() * 8));
81                    return serializer.serialize_str(&bitmask_names(enumeration, bits));
82                }
83                return SerializableField {
84                    mavtype: primitive,
85                    enumeration: None,
86                    bytes: &value.to_le_bytes()[..primitive.size()],
87                }
88                .serialize(serializer);
89            }
90
91            let (name, _) = enumeration
92                .entries
93                .iter()
94                .find(|(_, entry_value)| {
95                    *entry_value == value && enum_value_fits(self.mavtype, value)
96                })
97                .ok_or_else(|| {
98                    S::Error::custom(format!(
99                        "invalid enum value for {}: {value}",
100                        enumeration.name
101                    ))
102                })?;
103            let mut variant = serializer.serialize_map(Some(1))?;
104            variant.serialize_entry("type", name)?;
105            return variant.end();
106        }
107
108        match self.mavtype {
109            MavType::UInt8 | MavType::UInt8MavlinkVersion | MavType::Char => {
110                serializer.serialize_u8(self.bytes.first().copied().unwrap_or_default())
111            }
112            MavType::UInt16 => serializer.serialize_u16(u16::from_le_bytes(padded(self.bytes))),
113            MavType::UInt32 => serializer.serialize_u32(u32::from_le_bytes(padded(self.bytes))),
114            MavType::UInt64 => serializer.serialize_u64(u64::from_le_bytes(padded(self.bytes))),
115            MavType::Int8 => {
116                serializer.serialize_i8(self.bytes.first().copied().unwrap_or_default() as i8)
117            }
118            MavType::Int16 => serializer.serialize_i16(i16::from_le_bytes(padded(self.bytes))),
119            MavType::Int32 => serializer.serialize_i32(i32::from_le_bytes(padded(self.bytes))),
120            MavType::Int64 => serializer.serialize_i64(i64::from_le_bytes(padded(self.bytes))),
121            MavType::Float => serializer.serialize_f32(f32::from_le_bytes(padded(self.bytes))),
122            MavType::Double => serializer.serialize_f64(f64::from_le_bytes(padded(self.bytes))),
123            MavType::CharArray(_) | MavType::Array(_, _) => unreachable!(),
124        }
125    }
126}
127
128fn read_integer(mavtype: &MavType, bytes: &[u8]) -> Option<u64> {
129    cast_integer(mavtype, u64::from_le_bytes(padded(bytes)))
130}
131
132fn bitmask_names(enumeration: &DynamicEnumDefinition, value: u64) -> String {
133    let mut names = Vec::new();
134    let mut remaining = value;
135
136    for (name, bits) in &enumeration.entries {
137        let bits = *bits;
138        if bits != 0 && value & bits == bits && remaining & bits != 0 {
139            names.push(name.clone());
140            remaining &= !bits;
141        }
142    }
143
144    if remaining != 0 {
145        names.push(format!("0x{remaining:x}"));
146    }
147
148    names.join(" | ")
149}
150
151fn available_bytes(bytes: &[u8], offset: usize, length: usize) -> &[u8] {
152    let bytes = bytes.get(offset..).unwrap_or_default();
153    &bytes[..bytes.len().min(length)]
154}
155
156fn padded<const N: usize>(bytes: &[u8]) -> [u8; N] {
157    let mut padded = [0; N];
158    let length = N.min(bytes.len());
159    padded[..length].copy_from_slice(&bytes[..length]);
160    padded
161}
162
163#[cfg(test)]
164mod tests {
165    use super::{DynamicEnumDefinition, MavType, SerializableField};
166    use crate::dialects::dynamic_parser::write_value;
167
168    #[test]
169    fn bitmask_with_different_field_widths() {
170        let mut enumeration = DynamicEnumDefinition {
171            name: "Flags".into(),
172            primitive: Some(MavType::Int16),
173            entries: vec![("ENABLED".into(), 1)],
174        };
175        let json = serde_json::to_value(SerializableField {
176            mavtype: &MavType::Int8,
177            enumeration: Some(&enumeration),
178            bytes: &[255],
179        })
180        .unwrap();
181        let names = json.as_str().unwrap().into();
182        let mut output = [0];
183        write_value(&MavType::Int8, Some(&enumeration), &names, &mut output).unwrap();
184        assert_eq!(output, [255]);
185
186        enumeration.primitive = Some(MavType::UInt8);
187        for value in [256u16.into(), names] {
188            assert!(
189                write_value(&MavType::UInt16, Some(&enumeration), &value, &mut [0; 2]).is_err()
190            );
191        }
192    }
193}