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 #[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}