kafkaesque_macros/
derive_write.rs

1use darling::{ast::Data, FromDeriveInput, FromField};
2use proc_macro::TokenStream;
3use quote::quote;
4use std::iter;
5use syn::{parse, parse_macro_input, DeriveInput, Ident, Variant};
6
7#[derive(FromDeriveInput, Debug)]
8#[darling(supports(struct_named, struct_newtype, struct_unit))]
9struct Params {
10    ident: syn::Ident,
11    data: darling::ast::Data<Variant, StructField>,
12    generics: syn::Generics,
13}
14
15#[derive(Debug, Clone, FromField)]
16struct StructField {
17    ident: Option<Ident>,
18    // ty: Type,
19}
20
21pub fn expand(ts: TokenStream) -> TokenStream {
22    let derive_input = parse_macro_input!(ts as DeriveInput);
23    let params = Params::from_derive_input(&derive_input).expect("Failed to parse inputs");
24
25    let generics = params.generics;
26    let name = params.ident;
27    let fields = match params.data {
28        Data::Struct(fields) => fields,
29        Data::Enum(_) => unimplemented!("Unsupported"),
30    };
31
32    let impl_generics = {
33        let mut g = generics.clone();
34        for type_param in g.type_params_mut() {
35            type_param
36                .bounds
37                .push(parse(quote! { Write }.into()).unwrap());
38        }
39        g
40    };
41
42    let field_names: Vec<proc_macro2::TokenStream> = fields
43        .iter()
44        .map(|field| {
45            field
46                .ident
47                .clone()
48                .map(|ident| quote! {#ident})
49                .unwrap_or(quote! {0})
50        })
51        .collect();
52
53    let size_calculation: Vec<proc_macro2::TokenStream> = field_names
54        .iter()
55        .map(|name| {
56            quote! { Write::calculate_size(&self.#name) }
57        })
58        .chain(iter::once(quote! { 0 }))
59        .collect();
60
61    let writing: Vec<proc_macro2::TokenStream> = field_names
62        .iter()
63        .map(|name| {
64            quote! { Write::write_to(&self.#name, writer).await?;}
65        })
66        .collect();
67
68    let output = quote! {
69        #[automatically_derived]
70        impl #impl_generics crate::formats::codec::Write for #name #generics {
71            fn calculate_size(&self) -> i32 {
72                #(#size_calculation)+*
73            }
74            async fn write_to(&self, writer: &mut (dyn tokio::io::AsyncWrite + Send + Unpin)) -> crate::formats::Result<()> {
75                #(#writing) *
76                Ok(())
77            }
78        }
79    };
80
81    output.into()
82}