endify_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{DeriveInput, parse_macro_input};
4
5#[proc_macro_derive(Endify)]
6pub fn endify_derive(input: TokenStream) -> TokenStream {
7    // parse the input tokens into a syntax tree.
8    let input = parse_macro_input!(input as DeriveInput);
9
10    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
11
12    let to_le_impl = gen_method(&input, "to_le");
13    let to_be_impl = gen_method(&input, "to_be");
14    let from_le_impl = gen_method(&input, "from_le");
15    let from_be_impl = gen_method(&input, "from_be");
16
17    let name = &input.ident;
18
19    let expanded = quote! {
20        impl #impl_generics endify::Endify for #name #ty_generics #where_clause {
21                    #to_le_impl
22                    #to_be_impl
23                    #from_le_impl
24                    #from_be_impl
25        }
26    };
27
28    expanded.into()
29}
30
31/// Helper that generates the implementation of a given method.
32fn gen_method(input: &DeriveInput, method_name: &str) -> proc_macro2::TokenStream {
33    let method_ident = syn::Ident::new(method_name, proc_macro2::Span::call_site());
34    match &input.data {
35        syn::Data::Struct(data_struct) => match &data_struct.fields {
36            // named fields
37            syn::Fields::Named(fields) => {
38                let conversions = fields.named.iter().map(|field| {
39                    let ident = field.ident.as_ref().unwrap();
40                    quote! {
41                        #ident: Endify::#method_ident(self.#ident)
42                    }
43                });
44                quote! {
45                    fn #method_ident(self) -> Self {
46                        Self {
47                            #(#conversions),*
48                        }
49                    }
50                }
51            }
52            // tuple structs
53            syn::Fields::Unnamed(fields) => {
54                let conversions = fields.unnamed.iter().enumerate().map(|(i, _)| {
55                    let index = syn::Index::from(i);
56                    quote! {
57                        Endify::#method_ident(self.#index)
58                    }
59                });
60                quote! {
61                    fn #method_ident(self) -> Self {
62                        Self (
63                            #(#conversions),*
64                        )
65                    }
66                }
67            }
68            // unit structs
69            syn::Fields::Unit => {
70                quote! {
71                    fn #method_ident(self) -> Self {
72                        self
73                    }
74                }
75            }
76        },
77        _ => unimplemented!("only structs are supported right now. Feel free to open a PR."),
78    }
79}