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 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
31fn 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 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 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 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}