From 701f7723208b7c344c415968684d6ac774dc3cb4 Mon Sep 17 00:00:00 2001 From: Federico Lolli <federico.lolli@skywarder.eu> Date: Sat, 8 Mar 2025 13:22:23 +0000 Subject: [PATCH] Add get_field Method for Field Reflection --- mavlink-bindgen/Cargo.toml | 28 +++++++++++++----- mavlink-bindgen/src/parser.rs | 55 +++++++++++++++++++++++++++++++++++ mavlink-core/src/lib.rs | 4 ++- 3 files changed, 78 insertions(+), 9 deletions(-) diff --git a/mavlink-bindgen/Cargo.toml b/mavlink-bindgen/Cargo.toml index 2c23aee..80fcbb7 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 dce7263..feebda8 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 0cc5e87..e06a985 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 -- GitLab