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 let ty = &field.ty;
41 quote! {
42 #ident: #ty::#method_ident(self.#ident)
43 }
44 });
45 quote! {
46 fn #method_ident(self) -> Self {
47 Self {
48 #(#conversions),*
49 }
50 }
51 }
52 }
53 syn::Fields::Unnamed(fields) => {
55 let conversions = fields.unnamed.iter().enumerate().map(|(i, field)| {
56 let ty = &field.ty;
57 let index = syn::Index::from(i);
58 quote! {
59 #ty::#method_ident(self.#index)
60 }
61 });
62 quote! {
63 fn #method_ident(self) -> Self {
64 Self (
65 #(#conversions),*
66 )
67 }
68 }
69 }
70 syn::Fields::Unit => {
72 quote! {
73 fn #method_ident(self) -> Self {
74 self
75 }
76 }
77 }
78 },
79 _ => unimplemented!("only structs are supported right now. Feel free to open a PR."),
80 }
81}