1use syn::parse_quote;
2use utils::traitor::{Traitor, TraitorField};
3
4mod api;
5mod command;
6mod entity;
7mod enum_code;
8mod enum_int;
9mod flags;
10mod legacy;
11mod model;
12mod perms;
13mod routes;
14mod schema;
15mod utils;
16
17use proc_macro::TokenStream;
18
19#[proc_macro_derive(Command)]
30pub fn command(code: TokenStream) -> TokenStream {
31 command::command(code)
32}
33
34#[proc_macro_derive(EnumCode, attributes(enum_code))]
46pub fn enum_code(code: TokenStream) -> TokenStream {
47 enum_code::enum_code(code)
48}
49
50#[proc_macro_attribute]
99pub fn legacy(_args: TokenStream, code: TokenStream) -> TokenStream {
100 let item = syn::parse_macro_input!(code as syn::ItemMod);
101 legacy::legacy(item).unwrap_or_else(syn::Error::into_compile_error).into()
102}
103
104#[proc_macro_attribute]
119pub fn enum_int(args: TokenStream, code: TokenStream) -> TokenStream {
120 let item = syn::parse_macro_input!(code as syn::ItemEnum);
121 enum_int::enum_int(item, args)
122 .unwrap_or_else(syn::Error::into_compile_error)
123 .into()
124}
125
126#[proc_macro_attribute]
127pub fn api(args: TokenStream, code: TokenStream) -> TokenStream {
128 type Args = syn::punctuated::Punctuated<syn::MetaNameValue, syn::Token![,]>;
129 let item = syn::parse_macro_input!(code as syn::ItemMod);
130 let attrs = syn::parse_macro_input!(args with Args::parse_terminated);
131
132 api::api(attrs, item).unwrap_or_else(syn::Error::into_compile_error).into()
133}
134
135#[proc_macro_attribute]
136pub fn model(_args: TokenStream, code: TokenStream) -> TokenStream {
137 let item = syn::parse_macro_input!(code as syn::ItemStruct);
138 model::model(item).unwrap_or_else(syn::Error::into_compile_error).into()
139}
140
141#[proc_macro_attribute]
142pub fn flags(args: TokenStream, code: TokenStream) -> TokenStream {
143 let item = syn::parse_macro_input!(code as syn::ItemStruct);
144 let args = syn::parse_macro_input!(args with flags::Args::parse_terminated);
145 flags::flags(args, item)
146 .unwrap_or_else(syn::Error::into_compile_error)
147 .into()
148}
149
150#[proc_macro_derive(Entity, attributes(entity))]
151pub fn entity(code: TokenStream) -> TokenStream {
156 entity::entity(code)
157}
158
159#[proc_macro_derive(Belt, attributes(belt))]
160pub fn belt(code: TokenStream) -> TokenStream {
164 let ci = crate_ident();
165 let inp = syn::parse_macro_input!(code as syn::DeriveInput);
166
167 let gene = parse_quote!(#ci::models::Gene);
168
169 let tr = Traitor::new(
170 "belt",
171 parse_quote!(#ci::db::belt::Belt),
172 [
173 TraitorField::new("next", &gene, false),
174 TraitorField::new("past", &gene, false),
175 TraitorField::new("buckle", &gene, false),
176 ],
177 );
178 tr.derive(inp).unwrap_or_else(syn::Error::into_compile_error).into()
179}
180
181#[proc_macro_derive(Buckle, attributes(buckle))]
182pub fn buckle(code: TokenStream) -> TokenStream {
183 let ci = crate_ident();
184 let inp = syn::parse_macro_input!(code as syn::DeriveInput);
185
186 let gene = parse_quote!(#ci::models::Gene);
187 let pu64 = parse_quote!(u64);
188
189 let tr = Traitor::new(
190 "buckle",
191 parse_quote!(#ci::db::belt::Buckle),
192 [
193 TraitorField::new("head", &gene, false),
194 TraitorField::new("tail", &gene, false),
195 TraitorField::new("belt_count", &pu64, true),
196 ],
197 );
198 tr.derive(inp).unwrap_or_else(syn::Error::into_compile_error).into()
199}
200
201#[proc_macro_derive(Duck, attributes(duck))]
202pub fn duck(code: TokenStream) -> TokenStream {
203 let ci = crate_ident();
204 let inp = syn::parse_macro_input!(code as syn::DeriveInput);
205 let gene = parse_quote!(#ci::models::Gene);
206 let tr = Traitor::new(
207 "duck",
208 parse_quote!(#ci::db::pond::Duck),
209 [TraitorField::new("pond", &gene, false)],
210 );
211 tr.derive(inp).unwrap_or_else(syn::Error::into_compile_error).into()
212}
213
214#[proc_macro_derive(Pond, attributes(pond))]
215pub fn pond(code: TokenStream) -> TokenStream {
216 let ci = crate_ident();
217 let inp = syn::parse_macro_input!(code as syn::DeriveInput);
218
219 let gene = parse_quote!(#ci::models::Gene);
220 let pru8 = parse_quote!(u8);
221 let gene_id = parse_quote!(#ci::models::GeneId);
222
223 let tr = Traitor::new(
224 "pond",
225 parse_quote!(#ci::db::pond::Pond),
226 [
227 TraitorField::new("next", &gene, false),
228 TraitorField::new("past", &gene, false),
229 TraitorField::new("origin", &gene, false),
230 TraitorField::new("stack", &gene_id, true),
231 TraitorField::new("alive", &pru8, true),
232 TraitorField::new("empty", &pru8, true),
233 ],
234 );
235 tr.derive(inp).unwrap_or_else(syn::Error::into_compile_error).into()
236}
237
238#[proc_macro_derive(Origin, attributes(origin))]
239pub fn origin(code: TokenStream) -> TokenStream {
240 let ci = crate_ident();
241 let inp = syn::parse_macro_input!(code as syn::DeriveInput);
242
243 let gene = parse_quote!(#ci::models::Gene);
244 let pu64 = parse_quote!(u64);
245
246 let tr = Traitor::new(
247 "origin",
248 parse_quote!(#ci::db::pond::Origin),
249 [
250 TraitorField::new("head", &gene, false),
251 TraitorField::new("tail", &gene, false),
252 TraitorField::new("pond_count", &pu64, true),
253 TraitorField::new("item_count", &pu64, true),
254 ],
255 );
256 tr.derive(inp).unwrap_or_else(syn::Error::into_compile_error).into()
257}
258
259#[proc_macro_derive(ShahSchema)]
260pub fn schema(code: TokenStream) -> TokenStream {
261 schema::schema(code)
262}
263
264#[proc_macro]
265pub fn routes(code: TokenStream) -> TokenStream {
266 routes::routes(code)
267}
268
269#[proc_macro]
270pub fn perms(code: TokenStream) -> TokenStream {
271 perms::perms(code)
272}
273
274fn crate_ident() -> syn::Ident {
275 ident!("shah")
281}
282
283macro_rules! ident {
284 ($name:literal) => {
285 syn::Ident::new($name, proc_macro2::Span::call_site())
286 };
287 ($name:expr) => {
288 syn::Ident::new($name, proc_macro2::Span::call_site())
289 };
290}
291pub(crate) use ident;
292
293macro_rules! err {
294 ($span:expr, $($msg:literal),*) => {
295 Err(syn::Error::new($span, concat!( $($msg),* )))
296 };
297 ($span:expr, $msg:expr) => {
298 Err(syn::Error::new($span, $msg))
299 };
300}
301
302pub(crate) use err;