Rust过程宏技术求助:如何为已有枚举追加成员
Rust过程宏实现动态追加枚举成员问题
背景
使用rustdds crate实现DDS,通过枚举自定义领域参与者对接自定义主题(CustomTopic),枚举每个成员对应关联自定义可序列化数据类型的DataReader和DataWriter。最初尝试用HashMap<CustomTopic, DataReader<dyn Any>>(DataWriter同理),但因dyn Any或自定义可序列化 trait 的类型大小编译期无法确定,编译器报错。
临时解决方案
采用枚举实现,效果良好:既可以通过HashMap访问读写器,也能通过match匹配获取具体类型:
pub enum CustomDataReader { String(DataReader(String)), MyCustomDatatype(DataReader(MyCustomDatatype)), // MyCustomDatatype已实现序列化 } // 存储到HashMap let data_readers_hashmap = HashMap::<CustomTopic, CustomDataReader>::new();
匹配示例:
match datareader { CustomDataReader::String(dr) => { // dr类型为DataReader<String> }, CustomDataReader::MyCustomDatatype(dr) => { // dr类型为DataReader<MyCustomDatatype> }, }
但这种方式存在大量样板代码,因此尝试用过程宏优化。
理想效果
希望通过在结构体上添加#[derive(CustomDatatype)]派生宏,自动将结构体作为成员追加到预定义的CustomDataReader和CustomDataWriter枚举中:
#[derive(CustomDatatype)] struct Car { make: String, model: String, num_wheels: u8, } #[derive(CustomDatatype)] struct Building { name: String, location: (f32, f32), } // 预定义空枚举 pub enum CustomDataReader {} pub enum CustomDataWriter {}
宏自动生成后的枚举:
pub enum CustomDataReader { Car(DataReader(Car)), Building(DataReader(Building)), } pub enum CustomDataWriter { Car(DataWriter(Car)), Building(DataWriter(Building)), }
之后可通过CustomDataReader::Car等方式访问对应读写器。
失败尝试
实现的派生宏无法实现“追加到已有枚举”的功能,当前代码会重复定义枚举:
#[proc_macro_derive(CustomDatatype)] pub fn custom_datatype_derive(input: TokenStream) -> TokenStream { let input: DeriveInput = parse_macro_input!(input); let struct_name = &input.ident; let output = quote! { #input pub enum CustomDataReader { #struct_name(rustdds::no_key::DataReader<#struct_name>), } pub enum CustomDataWriter { #struct_name(rustdds::no_key::DataWriter<#struct_name>), } } output.into() }
生成的代码会重复定义枚举:
// 处理Car时生成 pub enum CustomDataReader { Car(DataReader(Car)), } pub enum CustomDataWriter { Car(DataWriter(Car)), } // 处理Building时生成 pub enum CustomDataReader { Building(DataReader(Building)), } pub enum CustomDataWriter { Building(DataWriter(Building)), }
不符合需求,尝试过其他宏类型仍无进展。
补充说明
曾尝试使用泛型和自定义 trait:
pub trait DDS_Msg: Serialize + for<'a> Deserialize<'a> + fmt::Display + Clone {} struct CustomDatatype {}; impl DDS_Msg for CustomDatatype {} pub struct Messenger { pub reader: Box<DataReader<dyn DDS_Msg>>, pub writer: Box<DataWriter<dyn DDS_Msg>>, }
但出现编译错误:
error[E0277]: the size for values of type `(dyn ddstypes::DDS_Msg + 'static)` cannot be known at compilation time --> src/utils/ddstypes.rs:123:17 | 123 | pub reader: Box<DataReader<dyn DDS_Msg>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn ddstypes::DDS_Msg + 'static)` note: required by a bound in `rustdds::no_key::DataReader` --> /home/user/.cargo/registry/src/github.com/rustdds-0.7.11/src/dds/no_key/datareader.rs:49:23 | 49 | pub struct DataReader<D: DeserializeOwned, DA: DeserializerAdapter<D> = CDRDeserializerAdapter<D>> { | ^ required by this bound in `rustdds::no_key::DataReader`
因此必须在编译期预定义数据类型,静态类型枚举是可行方案。
内容的提问来源于stack exchange,提问作者Arpad Voros
相关产品推荐
相关产品推荐

