1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#![warn(missing_debug_implementations, rust_2018_idioms)]
#![deny(rustdoc::broken_intra_doc_links)]
#![forbid(unsafe_code)]

use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use syn::{
	parse::{Parse, ParseStream},
	parse_macro_input,
	punctuated::Punctuated,
	DeriveInput, Meta, Result, Token
};

mod util;

mod endpoint;
use endpoint::{expand_endpoint, EndpointType};

mod from_body;
use from_body::expand_from_body;

mod request_body;
use request_body::expand_request_body;

mod resource;
use resource::expand_resource;

mod resource_error;
use resource_error::expand_resource_error;

mod private_openapi_trait;
use private_openapi_trait::expand_private_openapi_trait;

struct AttributeArgs(Punctuated<Meta, Token![,]>);

impl Parse for AttributeArgs {
	fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
		Ok(Self(Punctuated::parse_terminated(input)?))
	}
}

#[inline]
fn print_tokens(tokens: TokenStream2) -> TokenStream {
	// eprintln!("{tokens}");
	tokens.into()
}

#[inline]
fn expand_derive<F>(input: TokenStream, expand: F) -> TokenStream
where
	F: FnOnce(DeriveInput) -> Result<TokenStream2>
{
	print_tokens(expand(parse_macro_input!(input)).unwrap_or_else(|err| err.to_compile_error()))
}

#[inline]
fn expand_macro<F, A, I>(attrs: TokenStream, item: TokenStream, expand: F) -> TokenStream
where
	F: FnOnce(A, I) -> Result<TokenStream2>,
	A: Parse,
	I: Parse
{
	print_tokens(
		expand(parse_macro_input!(attrs), parse_macro_input!(item))
			.unwrap_or_else(|err| err.to_compile_error())
	)
}

#[proc_macro_derive(FromBody)]
pub fn derive_from_body(input: TokenStream) -> TokenStream {
	expand_derive(input, expand_from_body)
}

#[proc_macro_derive(RequestBody, attributes(supported_types))]
pub fn derive_request_body(input: TokenStream) -> TokenStream {
	expand_derive(input, expand_request_body)
}

#[proc_macro_derive(Resource, attributes(resource))]
pub fn derive_resource(input: TokenStream) -> TokenStream {
	expand_derive(input, expand_resource)
}

#[proc_macro_derive(ResourceError, attributes(display, from, status))]
pub fn derive_resource_error(input: TokenStream) -> TokenStream {
	expand_derive(input, expand_resource_error)
}

#[proc_macro_attribute]
pub fn endpoint(attr: TokenStream, item: TokenStream) -> TokenStream {
	expand_macro(attr, item, |attr, item| {
		expand_endpoint(EndpointType::custom(), attr, item)
	})
}

#[proc_macro_attribute]
pub fn read_all(attr: TokenStream, item: TokenStream) -> TokenStream {
	expand_macro(attr, item, |attr, item| {
		expand_endpoint(EndpointType::ReadAll, attr, item)
	})
}

#[proc_macro_attribute]
pub fn read(attr: TokenStream, item: TokenStream) -> TokenStream {
	expand_macro(attr, item, |attr, item| {
		expand_endpoint(EndpointType::Read, attr, item)
	})
}

#[proc_macro_attribute]
pub fn search(attr: TokenStream, item: TokenStream) -> TokenStream {
	expand_macro(attr, item, |attr, item| {
		expand_endpoint(EndpointType::Search, attr, item)
	})
}

#[proc_macro_attribute]
pub fn create(attr: TokenStream, item: TokenStream) -> TokenStream {
	expand_macro(attr, item, |attr, item| {
		expand_endpoint(EndpointType::Create, attr, item)
	})
}

#[proc_macro_attribute]
pub fn update_all(attr: TokenStream, item: TokenStream) -> TokenStream {
	expand_macro(attr, item, |attr, item| {
		expand_endpoint(EndpointType::UpdateAll, attr, item)
	})
}

#[proc_macro_attribute]
pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream {
	expand_macro(attr, item, |attr, item| {
		expand_endpoint(EndpointType::Update, attr, item)
	})
}

#[proc_macro_attribute]
pub fn delete_all(attr: TokenStream, item: TokenStream) -> TokenStream {
	expand_macro(attr, item, |attr, item| {
		expand_endpoint(EndpointType::DeleteAll, attr, item)
	})
}

#[proc_macro_attribute]
pub fn delete(attr: TokenStream, item: TokenStream) -> TokenStream {
	expand_macro(attr, item, |attr, item| {
		expand_endpoint(EndpointType::Delete, attr, item)
	})
}

/// PRIVATE MACRO - DO NOT USE
#[doc(hidden)]
#[proc_macro_attribute]
pub fn _private_openapi_trait(attr: TokenStream, item: TokenStream) -> TokenStream {
	expand_macro(attr, item, expand_private_openapi_trait)
}