typeshare_annotation/
lib.rs1extern crate proc_macro;
4use proc_macro::TokenStream;
5use quote::ToTokens;
6use syn::{parse, punctuated::Punctuated, Attribute, Data, DeriveInput, Fields, Meta, Token};
7
8#[proc_macro_attribute]
43pub fn typeshare(_attr: TokenStream, item: TokenStream) -> TokenStream {
44 if let Ok(mut item) = parse::<DeriveInput>(item.clone()) {
45 strip_configuration_attribute(&mut item);
47 TokenStream::from(item.to_token_stream())
48 } else {
49 item
50 }
51}
52
53const CONFIG_ATTRIBUTE_NAME: &str = "typeshare";
54
55fn is_typeshare_attribute(attribute: &Attribute) -> bool {
56 let has_cfg_attr = || {
57 if attribute.path().is_ident("cfg_attr") {
58 if let Ok(meta) =
59 attribute.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
60 {
61 return meta.into_iter().any(
62 |meta| matches!(meta, Meta::List(meta_list) if meta_list.path.is_ident(CONFIG_ATTRIBUTE_NAME)),
63 );
64 }
65 }
66 false
67 };
68 attribute.path().is_ident(CONFIG_ATTRIBUTE_NAME) || has_cfg_attr()
69}
70
71fn strip_configuration_attribute(item: &mut DeriveInput) {
72 fn remove_configuration_from_attributes(attributes: &mut Vec<Attribute>) {
73 attributes.retain(|attribute| !is_typeshare_attribute(attribute));
74 }
75
76 fn remove_configuration_from_fields(fields: &mut Fields) {
77 for field in fields.iter_mut() {
78 remove_configuration_from_attributes(&mut field.attrs);
79 }
80 }
81
82 match item.data {
83 Data::Enum(ref mut data_enum) => {
84 for variant in data_enum.variants.iter_mut() {
85 remove_configuration_from_attributes(&mut variant.attrs);
86 remove_configuration_from_fields(&mut variant.fields);
87 }
88 }
89 Data::Struct(ref mut data_struct) => {
90 remove_configuration_from_fields(&mut data_struct.fields);
91 }
92 Data::Union(ref mut data_union) => {
93 for field in data_union.fields.named.iter_mut() {
94 remove_configuration_from_attributes(&mut field.attrs);
95 }
96 }
97 };
98}