mavlink/dialects/
dynamic_serde.rs1use 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}