Skip to main content

anchor_cli_macros/
lib.rs

1use {
2    proc_macro2::TokenStream,
3    quote::{format_ident, quote},
4    syn::{parse_macro_input, DataEnum, DataStruct, DeriveInput, Fields},
5};
6
7#[proc_macro_derive(AbsolutePath)]
8pub fn absolute_path_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
9    let input = parse_macro_input!(input as DeriveInput);
10    let constructor = match input.data {
11        syn::Data::Struct(data_struct) => derive_struct(data_struct),
12        syn::Data::Enum(data_enum) => derive_enum(data_enum),
13        syn::Data::Union(_) => {
14            quote! { compile_error!("unions are not supported") }
15        }
16    };
17    let name = input.ident;
18
19    quote! {
20        // Some fields/commands in the CLI are deprecated
21        #[allow(deprecated)]
22        impl AbsolutePath for #name {
23            fn absolute(self) -> Self {
24                #constructor
25            }
26        }
27    }
28    .into()
29}
30
31fn derive_struct(input: DataStruct) -> TokenStream {
32    match input.fields {
33        Fields::Named(fields) => {
34            let members: Vec<_> = fields
35                .named
36                .into_iter()
37                .map(|field| field.ident.expect("named field"))
38                .collect();
39            quote! {
40                Self {
41                    #(#members: self.#members.absolute()),*
42                }
43            }
44        }
45        Fields::Unnamed(fields) => {
46            let members: Vec<_> = (0..fields.unnamed.len()).map(syn::Index::from).collect();
47            quote! {
48                Self(
49                    #(self.#members.absolute()),*
50                )
51            }
52        }
53        Fields::Unit => quote! { Self },
54    }
55}
56
57fn derive_enum(input: DataEnum) -> TokenStream {
58    let variants = input.variants.into_iter().map(|variant| {
59        let name = variant.ident;
60        match variant.fields {
61            Fields::Named(fields) => {
62                let members: Vec<_> = fields
63                    .named
64                    .into_iter()
65                    .map(|field| field.ident.expect("named field"))
66                    .collect();
67                quote! {
68                    Self::#name { #(#members),* } => Self::#name {
69                        #(#members: #members.absolute()),*
70                    }
71                }
72            }
73            Fields::Unnamed(fields) => {
74                let members: Vec<_> = (0..fields.unnamed.len())
75                    .map(|index| format_ident!("field_{index}"))
76                    .collect();
77                quote! {
78                    Self::#name(#(#members),*) => Self::#name(
79                        #(#members.absolute()),*
80                    )
81                }
82            }
83            Fields::Unit => quote! {
84                Self::#name => Self::#name
85            },
86        }
87    });
88    quote! {
89        match self {
90            #(#variants),*
91        }
92    }
93}