Skip to content

Commit b33ce10

Browse files
authored
Add wrapper for char arrays to access str conveniently (#388)
* Add wrapper for char arrays to access str conveniently This adds a wrapper around char arrays that allows to access them either as slices or as strings. When accessing the string representation, it will automatically convert the char array to a string slice up to the first null byte. * Implement RustDefault for CharArray * Fix review comments * Fix tests * Fix formatting * Fix ts annotation for CharArray * Fix merge conflicts and change serialization * Avoid unnecessary find
1 parent 1dc53cc commit b33ce10

9 files changed

Lines changed: 236 additions & 78 deletions

mavlink-bindgen/src/parser.rs

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ impl MavProfile {
215215
#[allow(unused_imports)]
216216
use bitflags::bitflags;
217217

218-
use mavlink_core::{MavlinkVersion, Message, MessageData, bytes::Bytes, bytes_mut::BytesMut};
218+
use mavlink_core::{MavlinkVersion, Message, MessageData, bytes::Bytes, bytes_mut::BytesMut, types::CharArray};
219219

220220
#[cfg(feature = "serde")]
221221
use serde::{Serialize, Deserialize};
@@ -710,23 +710,15 @@ impl MavMessage {
710710
quote!()
711711
};
712712

713-
let serde_with_attr = if let MavType::Array(_, size) = field.mavtype {
714-
if field.mavtype.primitive_type() == "char" {
715-
let format_serialize = format!("crate::nulstr::serialize::<_, {}>", size);
716-
let format_deserialize = format!("crate::nulstr::deserialize::<_, {}>", size);
717-
quote!(
718-
#[cfg_attr(feature = "serde", serde(
719-
serialize_with = #format_serialize,
720-
deserialize_with = #format_deserialize
721-
))]
722-
#[cfg_attr(feature = "ts", ts(type = "string"))]
723-
)
724-
} else {
725-
quote!(
726-
#[cfg_attr(feature = "serde", serde(with = "serde_arrays"))]
727-
#[cfg_attr(feature = "ts", ts(type = "Array<number>"))]
728-
)
729-
}
713+
let serde_with_attr = if matches!(field.mavtype, MavType::Array(_, _)) {
714+
quote!(
715+
#[cfg_attr(feature = "serde", serde(with = "serde_arrays"))]
716+
#[cfg_attr(feature = "ts", ts(type = "Array<number>"))]
717+
)
718+
} else if matches!(field.mavtype, MavType::CharArray(_)) {
719+
quote!(
720+
#[cfg_attr(feature = "ts", ts(type = "string"))]
721+
)
730722
} else {
731723
quote!()
732724
};
@@ -1113,6 +1105,7 @@ pub enum MavType {
11131105
Char,
11141106
Float,
11151107
Double,
1108+
CharArray(usize),
11161109
Array(Box<MavType>, usize),
11171110
}
11181111

@@ -1133,16 +1126,18 @@ impl MavType {
11331126
"float" => Some(Float),
11341127
"Double" => Some(Double),
11351128
"double" => Some(Double),
1136-
_ => {
1137-
if s.ends_with(']') {
1138-
let start = s.find('[')?;
1139-
let size = s[start + 1..(s.len() - 1)].parse::<usize>().ok()?;
1140-
let mtype = Self::parse_type(&s[0..start])?;
1141-
Some(Array(Box::new(mtype), size))
1142-
} else {
1143-
None
1144-
}
1129+
_ if s.starts_with("char[") => {
1130+
let start = 4;
1131+
let size = s[start + 1..(s.len() - 1)].parse::<usize>().ok()?;
1132+
Some(CharArray(size))
11451133
}
1134+
_ if s.ends_with(']') => {
1135+
let start = s.find('[')?;
1136+
let size = s[start + 1..(s.len() - 1)].parse::<usize>().ok()?;
1137+
let mtype = Self::parse_type(&s[0..start])?;
1138+
Some(Array(Box::new(mtype), size))
1139+
}
1140+
_ => None,
11461141
}
11471142
}
11481143

@@ -1162,6 +1157,15 @@ impl MavType {
11621157
Int64 => quote! {#val = #buf.get_i64_le();},
11631158
Float => quote! {#val = #buf.get_f32_le();},
11641159
Double => quote! {#val = #buf.get_f64_le();},
1160+
CharArray(size) => {
1161+
quote! {
1162+
let mut tmp = [0_u8; #size];
1163+
for v in &mut tmp {
1164+
*v = #buf.get_u8();
1165+
}
1166+
#val = CharArray::new(tmp);
1167+
}
1168+
}
11651169
Array(t, _) => {
11661170
let r = t.rust_reader(&quote!(let val), buf);
11671171
quote! {
@@ -1190,6 +1194,14 @@ impl MavType {
11901194
UInt64 => quote! {#buf.put_u64_le(#val);},
11911195
Int64 => quote! {#buf.put_i64_le(#val);},
11921196
Double => quote! {#buf.put_f64_le(#val);},
1197+
CharArray(_) => {
1198+
let w = Char.rust_writer(&quote!(*val), buf);
1199+
quote! {
1200+
for val in &#val {
1201+
#w
1202+
}
1203+
}
1204+
}
11931205
Array(t, _size) => {
11941206
let w = t.rust_writer(&quote!(*val), buf);
11951207
quote! {
@@ -1209,6 +1221,7 @@ impl MavType {
12091221
UInt16 | Int16 => 2,
12101222
UInt32 | Int32 | Float => 4,
12111223
UInt64 | Int64 | Double => 8,
1224+
CharArray(size) => *size,
12121225
Array(t, size) => t.len() * size,
12131226
}
12141227
}
@@ -1217,7 +1230,7 @@ impl MavType {
12171230
fn order_len(&self) -> usize {
12181231
use self::MavType::*;
12191232
match self {
1220-
UInt8MavlinkVersion | UInt8 | Int8 | Char => 1,
1233+
UInt8MavlinkVersion | UInt8 | Int8 | Char | CharArray(_) => 1,
12211234
UInt16 | Int16 => 2,
12221235
UInt32 | Int32 | Float => 4,
12231236
UInt64 | Int64 | Double => 8,
@@ -1241,6 +1254,7 @@ impl MavType {
12411254
UInt64 => "uint64_t".into(),
12421255
Int64 => "int64_t".into(),
12431256
Double => "double".into(),
1257+
CharArray(_) => "char".into(),
12441258
Array(t, _) => t.primitive_type(),
12451259
}
12461260
}
@@ -1261,6 +1275,7 @@ impl MavType {
12611275
UInt64 => "u64".into(),
12621276
Int64 => "i64".into(),
12631277
Double => "f64".into(),
1278+
CharArray(size) => format!("CharArray<{}>", size),
12641279
Array(t, size) => format!("[{};{}]", t.rust_type(), size),
12651280
}
12661281
}
@@ -1286,6 +1301,7 @@ impl MavType {
12861301
UInt64 => quote!(0_u64),
12871302
Int64 => quote!(0_i64),
12881303
Double => quote!(0.0_f64),
1304+
CharArray(size) => quote!(CharArray::new([0_u8; #size])),
12891305
Array(ty, size) => {
12901306
let default_value = ty.emit_default_value(dialect_has_version);
12911307
quote!([#default_value; #size])
@@ -1866,7 +1882,7 @@ pub fn extra_crc(msg: &MavMessage) -> u8 {
18661882
crc.digest(field.name.as_bytes());
18671883
}
18681884
crc.digest(b" ");
1869-
if let MavType::Array(_, size) = field.mavtype {
1885+
if let MavType::Array(_, size) | MavType::CharArray(size) = field.mavtype {
18701886
crc.digest(&[size as u8]);
18711887
}
18721888
}

mavlink-bindgen/tests/snapshots/e2e_snapshots__deprecated.xml@deprecated.rs.snap

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
---
22
source: mavlink-bindgen/tests/e2e_snapshots.rs
3-
assertion_line: 26
43
expression: contents
54
---
65
#![doc = "MAVLink deprecated dialect."]
@@ -11,7 +10,9 @@ expression: contents
1110
use arbitrary::Arbitrary;
1211
#[allow(unused_imports)]
1312
use bitflags::bitflags;
14-
use mavlink_core::{bytes::Bytes, bytes_mut::BytesMut, MavlinkVersion, Message, MessageData};
13+
use mavlink_core::{
14+
bytes::Bytes, bytes_mut::BytesMut, types::CharArray, MavlinkVersion, Message, MessageData,
15+
};
1516
#[allow(unused_imports)]
1617
use num_derive::FromPrimitive;
1718
#[allow(unused_imports)]

mavlink-bindgen/tests/snapshots/e2e_snapshots__heartbeat.xml@heartbeat.rs.snap

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ expression: contents
1111
use arbitrary::Arbitrary;
1212
#[allow(unused_imports)]
1313
use bitflags::bitflags;
14-
use mavlink_core::{bytes::Bytes, bytes_mut::BytesMut, MavlinkVersion, Message, MessageData};
14+
use mavlink_core::{
15+
bytes::Bytes, bytes_mut::BytesMut, types::CharArray, MavlinkVersion, Message, MessageData,
16+
};
1517
#[allow(unused_imports)]
1618
use num_derive::FromPrimitive;
1719
#[allow(unused_imports)]

mavlink-bindgen/tests/snapshots/e2e_snapshots__no_field_description.xml@no_field_description.rs.snap

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
---
22
source: mavlink-bindgen/tests/e2e_snapshots.rs
3-
assertion_line: 26
43
expression: contents
54
---
65
#![doc = "MAVLink no_field_description dialect."]
@@ -11,7 +10,9 @@ expression: contents
1110
use arbitrary::Arbitrary;
1211
#[allow(unused_imports)]
1312
use bitflags::bitflags;
14-
use mavlink_core::{bytes::Bytes, bytes_mut::BytesMut, MavlinkVersion, Message, MessageData};
13+
use mavlink_core::{
14+
bytes::Bytes, bytes_mut::BytesMut, types::CharArray, MavlinkVersion, Message, MessageData,
15+
};
1516
#[allow(unused_imports)]
1617
use num_derive::FromPrimitive;
1718
#[allow(unused_imports)]

mavlink-bindgen/tests/snapshots/e2e_snapshots__parameters.xml@parameters.rs.snap

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
---
22
source: mavlink-bindgen/tests/e2e_snapshots.rs
3-
assertion_line: 26
43
expression: contents
54
---
65
#![doc = "MAVLink parameters dialect."]
@@ -11,7 +10,9 @@ expression: contents
1110
use arbitrary::Arbitrary;
1211
#[allow(unused_imports)]
1312
use bitflags::bitflags;
14-
use mavlink_core::{bytes::Bytes, bytes_mut::BytesMut, MavlinkVersion, Message, MessageData};
13+
use mavlink_core::{
14+
bytes::Bytes, bytes_mut::BytesMut, types::CharArray, MavlinkVersion, Message, MessageData,
15+
};
1516
#[allow(unused_imports)]
1617
use num_derive::FromPrimitive;
1718
#[allow(unused_imports)]
@@ -156,23 +157,16 @@ pub struct PARAM_REQUEST_READ_DATA {
156157
#[doc = "Component ID"]
157158
pub target_component: u8,
158159
#[doc = "Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string"]
159-
#[cfg_attr(
160-
feature = "serde",
161-
serde(
162-
serialize_with = "crate::nulstr::serialize::<_, 16>",
163-
deserialize_with = "crate::nulstr::deserialize::<_, 16>"
164-
)
165-
)]
166160
#[cfg_attr(feature = "ts", ts(type = "string"))]
167-
pub param_id: [u8; 16],
161+
pub param_id: CharArray<16>,
168162
}
169163
impl PARAM_REQUEST_READ_DATA {
170164
pub const ENCODED_LEN: usize = 20usize;
171165
pub const DEFAULT: Self = Self {
172166
param_index: 0_i16,
173167
target_system: 0_u8,
174168
target_component: 0_u8,
175-
param_id: [0_u8; 16usize],
169+
param_id: CharArray::new([0_u8; 16usize]),
176170
};
177171
#[cfg(feature = "arbitrary")]
178172
pub fn random<R: rand::RngCore>(rng: &mut R) -> Self {
@@ -210,10 +204,11 @@ impl MessageData for PARAM_REQUEST_READ_DATA {
210204
__struct.param_index = buf.get_i16_le();
211205
__struct.target_system = buf.get_u8();
212206
__struct.target_component = buf.get_u8();
213-
for v in &mut __struct.param_id {
214-
let val = buf.get_u8();
215-
*v = val;
207+
let mut tmp = [0_u8; 16usize];
208+
for v in &mut tmp {
209+
*v = buf.get_u8();
216210
}
211+
__struct.param_id = CharArray::new(tmp);
217212
Ok(__struct)
218213
}
219214
fn ser(&self, version: MavlinkVersion, bytes: &mut [u8]) -> usize {
@@ -257,15 +252,8 @@ pub struct PARAM_SET_DATA {
257252
#[doc = "Component ID"]
258253
pub target_component: u8,
259254
#[doc = "Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string"]
260-
#[cfg_attr(
261-
feature = "serde",
262-
serde(
263-
serialize_with = "crate::nulstr::serialize::<_, 16>",
264-
deserialize_with = "crate::nulstr::deserialize::<_, 16>"
265-
)
266-
)]
267255
#[cfg_attr(feature = "ts", ts(type = "string"))]
268-
pub param_id: [u8; 16],
256+
pub param_id: CharArray<16>,
269257
#[doc = "Onboard parameter type."]
270258
pub param_type: MavParamType,
271259
}
@@ -275,7 +263,7 @@ impl PARAM_SET_DATA {
275263
param_value: 0.0_f32,
276264
target_system: 0_u8,
277265
target_component: 0_u8,
278-
param_id: [0_u8; 16usize],
266+
param_id: CharArray::new([0_u8; 16usize]),
279267
param_type: MavParamType::DEFAULT,
280268
};
281269
#[cfg(feature = "arbitrary")]
@@ -314,10 +302,11 @@ impl MessageData for PARAM_SET_DATA {
314302
__struct.param_value = buf.get_f32_le();
315303
__struct.target_system = buf.get_u8();
316304
__struct.target_component = buf.get_u8();
317-
for v in &mut __struct.param_id {
318-
let val = buf.get_u8();
319-
*v = val;
305+
let mut tmp = [0_u8; 16usize];
306+
for v in &mut tmp {
307+
*v = buf.get_u8();
320308
}
309+
__struct.param_id = CharArray::new(tmp);
321310
let tmp = buf.get_u8();
322311
__struct.param_type =
323312
FromPrimitive::from_u8(tmp).ok_or(::mavlink_core::error::ParserError::InvalidEnum {
@@ -368,15 +357,8 @@ pub struct PARAM_VALUE_DATA {
368357
#[doc = "Index of this onboard parameter"]
369358
pub param_index: u16,
370359
#[doc = "Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string"]
371-
#[cfg_attr(
372-
feature = "serde",
373-
serde(
374-
serialize_with = "crate::nulstr::serialize::<_, 16>",
375-
deserialize_with = "crate::nulstr::deserialize::<_, 16>"
376-
)
377-
)]
378360
#[cfg_attr(feature = "ts", ts(type = "string"))]
379-
pub param_id: [u8; 16],
361+
pub param_id: CharArray<16>,
380362
#[doc = "Onboard parameter type."]
381363
pub param_type: MavParamType,
382364
}
@@ -386,7 +368,7 @@ impl PARAM_VALUE_DATA {
386368
param_value: 0.0_f32,
387369
param_count: 0_u16,
388370
param_index: 0_u16,
389-
param_id: [0_u8; 16usize],
371+
param_id: CharArray::new([0_u8; 16usize]),
390372
param_type: MavParamType::DEFAULT,
391373
};
392374
#[cfg(feature = "arbitrary")]
@@ -425,10 +407,11 @@ impl MessageData for PARAM_VALUE_DATA {
425407
__struct.param_value = buf.get_f32_le();
426408
__struct.param_count = buf.get_u16_le();
427409
__struct.param_index = buf.get_u16_le();
428-
for v in &mut __struct.param_id {
429-
let val = buf.get_u8();
430-
*v = val;
410+
let mut tmp = [0_u8; 16usize];
411+
for v in &mut tmp {
412+
*v = buf.get_u8();
431413
}
414+
__struct.param_id = CharArray::new(tmp);
432415
let tmp = buf.get_u8();
433416
__struct.param_type =
434417
FromPrimitive::from_u8(tmp).ok_or(::mavlink_core::error::ParserError::InvalidEnum {

mavlink-core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ pub mod bytes_mut;
113113
#[cfg(feature = "std")]
114114
mod connection;
115115
pub mod error;
116+
pub mod types;
116117
#[cfg(feature = "std")]
117118
pub use self::connection::{connect, Connectable, MavConnection};
118119

0 commit comments

Comments
 (0)