Skip to main content

paperless_api_macros/
lib.rs

1mod derive_base;
2mod repr_serde;
3
4use proc_macro::TokenStream;
5use quote::{format_ident, quote};
6use syn::{DeriveInput, parse_macro_input};
7
8use crate::derive_base::BaseStruct;
9
10/// Derives a `Create..` struct for the given input struct.
11#[proc_macro_derive(CreateDto, attributes(dto, api_info))]
12pub fn derive_create_dto(input: TokenStream) -> TokenStream {
13    // Parse the input
14    let input = parse_macro_input!(input as DeriveInput);
15    let input_struct = match BaseStruct::try_from(input) {
16        Ok(val) => val,
17        Err(e) => return e.to_compile_error().into(),
18    };
19
20    // Generate the new struct
21    let new_struct_name = format_ident!("Create{}", input_struct.name);
22    let new_struct = input_struct.generate_new_struct(&new_struct_name, false);
23
24    let id_type_name = input_struct.id_type;
25    let id_type_name = quote!(crate::id::#id_type_name);
26
27    let name = input_struct.name;
28
29    // Generate the final output with the trait implementation
30    TokenStream::from(quote! {
31        #new_struct
32
33        #[automatically_derived]
34        impl crate::dto::CreateDto for #new_struct_name {
35            type Id = #id_type_name;
36            type BaseType = #name;
37        }
38    })
39}
40
41/// Derives a `Update..` struct for the given input struct.
42#[proc_macro_derive(UpdateDto, attributes(dto, api_info))]
43pub fn derive_update_dto(input: TokenStream) -> TokenStream {
44    // Parse the input
45    let input = parse_macro_input!(input as DeriveInput);
46    let input_struct = match BaseStruct::try_from(input) {
47        Ok(val) => val,
48        Err(e) => return e.to_compile_error().into(),
49    };
50
51    // Generate the new struct
52    let new_struct_name = format_ident!("Update{}", input_struct.name);
53    let new_struct = input_struct.generate_new_struct(&new_struct_name, true);
54
55    let id_type_name = input_struct.id_type;
56    let id_type_name = quote!(crate::id::#id_type_name);
57
58    let name = input_struct.name;
59
60    // Generate the final output with the trait implementation
61    TokenStream::from(quote! {
62        #new_struct
63
64        #[automatically_derived]
65        impl crate::dto::UpdateDto for #new_struct_name {
66            type Id = #id_type_name;
67            type BaseType = #name;
68        }
69    })
70}
71
72/// Derives `Item` trait for the given input struct.
73#[proc_macro_derive(Item, attributes(dto, api_info))]
74pub fn derive_item_trait(input: TokenStream) -> TokenStream {
75    // Parse the input
76    let input = parse_macro_input!(input as DeriveInput);
77    let input_struct = match BaseStruct::try_from(input) {
78        Ok(val) => val,
79        Err(e) => return e.to_compile_error().into(),
80    };
81
82    let id_type_name = format_ident!("{}Id", input_struct.name);
83    let id_type_name = quote!(crate::id::#id_type_name);
84
85    let endpoint = input_struct.endpoint.clone();
86    let name = input_struct.name;
87
88    // Generate the final output with the trait implementation
89    TokenStream::from(quote! {
90        #[automatically_derived]
91        impl crate::dto::Item for #name {
92            type Id = #id_type_name;
93            type BaseType = #name;
94
95            #[inline]
96            fn endpoint() -> &'static str {
97                #endpoint
98            }
99
100            #[inline]
101            fn id(&self) -> Self::Id {
102                self.id
103            }
104        }
105    })
106}
107
108/// Derives `Serialize` and `Deserialize` by reading discriminant values
109/// directly from the AST.
110///
111/// The enum must have exactly one data-carrying variant (e.g. `Unknown(u8)`)
112/// which is used as the fallback for unknown values.
113#[proc_macro_derive(ReprSerde)]
114pub fn derive_repr_serde(input: TokenStream) -> TokenStream {
115    let input = parse_macro_input!(input as DeriveInput);
116
117    let repr_enum = match repr_serde::ReprEnum::try_from(input) {
118        Ok(val) => val,
119        Err(e) => return e.to_compile_error().into(),
120    };
121
122    TokenStream::from(repr_enum.generate())
123}