diff --git a/mavlink-bindgen/Cargo.toml b/mavlink-bindgen/Cargo.toml index 2c23aeefaac642164116a901d7ed33451b2d4663..80fcbb71ba41f5a54ad0492ffe1263720476c686 100644 --- a/mavlink-bindgen/Cargo.toml +++ b/mavlink-bindgen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mavlink-bindgen" -version = "0.13.2" +version = "0.14.0" edition.workspace = true license = "MIT/Apache-2.0" description = "Library used by rust-mavlink." @@ -17,17 +17,29 @@ quote = "1" proc-macro2 = "1.0.43" lazy_static = "1.2.0" serde = { version = "1.0.115", optional = true, features = ["derive"] } -clap = { version = "~4.3.24", optional = true, default-features =false, features = ["derive", "help", "usage", "error-context"] } +clap = { version = "~4.3.24", optional = true, default-features = false, features = [ + "derive", + "help", + "usage", + "error-context", +] } thiserror = "1.0.56" # Required to support MSRV 1.65.0 -clap_lex = { version = "=0.5.0", optional=true } -clap_builder = { version = "~4.3.24", optional=true} -anstyle = { version = "=1.0.2", optional=true } -anstyle-query = { version = "=1.0.0", optional=true } -anstyle-parse = { version = "=0.2.1", optional=true } +clap_lex = { version = "=0.5.0", optional = true } +clap_builder = { version = "~4.3.24", optional = true } +anstyle = { version = "=1.0.2", optional = true } +anstyle-query = { version = "=1.0.0", optional = true } +anstyle-parse = { version = "=0.2.1", optional = true } [features] -cli = ["dep:clap", "dep:clap_lex", "dep:clap_builder", "dep:anstyle", "dep:anstyle-query", "dep:anstyle-parse"] +cli = [ + "dep:clap", + "dep:clap_lex", + "dep:clap_builder", + "dep:anstyle", + "dep:anstyle-query", + "dep:anstyle-parse", +] emit-extensions = [] emit-description = [] diff --git a/mavlink-bindgen/src/parser.rs b/mavlink-bindgen/src/parser.rs index dce7263129824670660dcc195a8734b59ecce0d5..feebda8e6aceeb15a565ee5fa15c621855b6a26c 100644 --- a/mavlink-bindgen/src/parser.rs +++ b/mavlink-bindgen/src/parser.rs @@ -138,6 +138,7 @@ impl MavProfile { let mav_message_default_from_id = self.emit_mav_message_default_from_id(&enum_names, &struct_names); let mav_message_serialize = self.emit_mav_message_serialize(&enum_names); + let mav_message_get_field = self.emit_mav_message_get_field(&enum_names); quote! { #comment @@ -152,6 +153,8 @@ impl MavProfile { #[allow(unused_imports)] use bitflags::bitflags; + use std::any::Any; + use mavlink_core::{MavlinkVersion, Message, MessageData, bytes::Bytes, bytes_mut::BytesMut}; #[cfg(feature = "serde")] @@ -172,6 +175,7 @@ impl MavProfile { #mav_message_default_from_id #mav_message_serialize #mav_message_crc + #mav_message_get_field } } } @@ -279,6 +283,16 @@ impl MavProfile { } } } + + fn emit_mav_message_get_field(&self, enums: &[TokenStream]) -> TokenStream { + quote! { + fn get_field(&self, index: usize) -> Option<Box<dyn Any>> { + match self { + #(Self::#enums(body) => body.get_field(index),)* + } + } + } + } } #[derive(Debug, PartialEq, Eq, Clone, Default)] @@ -565,6 +579,44 @@ impl MavMessage { } } + fn emit_get_field_impl(&self) -> TokenStream { + let field_names = self + .fields + .iter() + .enumerate() + .map(|(i, f)| { + let name = f.emit_name(); + quote! {#i => Some(Box::new(self.#name)),} + }) + .collect::<Vec<TokenStream>>(); + + let body = if field_names.is_empty() { + // struct has no fields + quote! { + None + } + } else { + quote! { + match index { + #(#field_names)* + _ => None, + } + } + }; + + let arg_name = if self.fields.is_empty() { + quote! {_index} + } else { + quote! {index} + }; + + quote! { + fn get_field(&self, #arg_name: usize) -> Option<Box<dyn Any>> { + #body + } + } + } + fn emit_default_impl(&self) -> TokenStream { let msg_name = self.emit_struct_name(); quote! { @@ -595,6 +647,7 @@ impl MavMessage { let serialize_vars = self.emit_serialize_vars(); let const_default = self.emit_const_default(); let default_impl = self.emit_default_impl(); + let get_field_impl = self.emit_get_field_impl(); #[cfg(feature = "emit-description")] let description = self.emit_description(); @@ -632,6 +685,8 @@ impl MavMessage { fn ser(&self, version: MavlinkVersion, bytes: &mut [u8]) -> usize { #serialize_vars } + + #get_field_impl } } } diff --git a/mavlink-core/src/lib.rs b/mavlink-core/src/lib.rs index 0cc5e877853f34aba8089d2548080cce55ac1e6d..e06a985e5668b970c773a53744b9a8e556b0e7c6 100644 --- a/mavlink-core/src/lib.rs +++ b/mavlink-core/src/lib.rs @@ -23,7 +23,7 @@ #![deny(clippy::all)] #![warn(clippy::use_self)] -use core::result::Result; +use core::{any::Any, result::Result}; #[cfg(feature = "std")] use std::io::{Read, Write}; @@ -102,6 +102,7 @@ where fn message_id_from_name(name: &str) -> Result<u32, &'static str>; fn default_message_from_id(id: u32) -> Result<Self, &'static str>; fn extra_crc(id: u32) -> u8; + fn get_field(&self, index: usize) -> Option<Box<dyn Any>>; } pub trait MessageData: Sized { @@ -114,6 +115,7 @@ pub trait MessageData: Sized { fn ser(&self, version: MavlinkVersion, payload: &mut [u8]) -> usize; fn deser(version: MavlinkVersion, payload: &[u8]) -> Result<Self, ParserError>; + fn get_field(&self, index: usize) -> Option<Box<dyn Any>>; } /// Metadata from a MAVLink packet header