1use proc_macro::TokenStream;
203
204mod atd;
205mod deserialize;
206mod handler;
207mod serialize;
208
209use quote::quote;
210use syn::{
211 Attribute, Data, DeriveInput, FnArg, ItemFn, LitInt, LitStr, Meta, PatType, Token,
212 parse::{Parse, ParseStream},
213 parse_macro_input,
214 punctuated::Punctuated,
215 spanned::Spanned as _,
216};
217
218#[proc_macro_attribute]
220pub fn handler(attr: TokenStream, item: TokenStream) -> TokenStream {
221 atd::handler(attr, item)
222}
223
224#[proc_macro]
226pub fn register(input: TokenStream) -> TokenStream {
227 atd::register(input)
228}
229
230#[proc_macro_attribute]
231pub fn middleware(_attr: TokenStream, input: TokenStream) -> TokenStream {
232 let input = parse_macro_input!(input as ItemFn);
233
234 let ident = &input.sig.ident;
235 let vis = &input.vis;
236 let block = &input.block;
237 let sig = &input.sig;
238 let mut state_ty = None;
239 let mut header_ty = None;
240 for (i, arg) in sig.inputs.iter().enumerate() {
241 if let FnArg::Typed(PatType { ty, .. }) = arg {
242 match i {
243 0 => state_ty = Some(ty.clone()),
244 1 => header_ty = Some(ty.clone()),
245 _ => {}
246 }
247 }
248 }
249
250 let state_ty = state_ty.expect("Expected first parameter to be state");
251 let header_ty = header_ty.expect("Expected second parameter to be header");
252
253 TokenStream::from(quote! {
254 #vis fn #ident() -> Box<afast::Middleware<#state_ty, #header_ty>> {
255 Box::new(|state, header| Box::pin(async move {
256 #block
257 }))
258 }
259 })
260}
261
262#[proc_macro_derive(AFastData, attributes(validate, afast))]
264pub fn serialize_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
265 let input = parse_macro_input!(input as DeriveInput);
266 let name = input.ident;
267 let mut code = Vec::new();
268
269 let (serialize_code, deserialize_code, validate_code) = match &input.data {
270 Data::Struct(data) => match handler::rust::handler_struct(&name, data) {
271 Ok(ts) => ts,
272 Err(e) => return e.to_compile_error().into(),
273 },
274 Data::Enum(data) => match handler::rust::handler_enum(&name, data) {
275 Ok(ts) => ts,
276 Err(e) => return e.to_compile_error().into(),
277 },
278 Data::Union(_data) => panic!("unions are not supported yet"),
279 };
280
281 code.push(quote! {
282 fn to_bytes(&self) -> Vec<u8> {
283 let mut buf = Vec::new();
284 #(#serialize_code)*
285 buf
286 }
287
288 fn from_bytes(buf: &[u8]) -> Result<(Self, usize), ::afast::Error> {
289 let _length = buf.len();
290 let mut _offset = 0;
291 #(#deserialize_code)*
292 }
293
294 fn validate(&self) -> Result<(), Vec<&'static str>> {
295 #(#validate_code)*
296 Ok(())
297 }
298 });
299
300 let expanded = quote! {
301 impl ::afast::AFastData for #name {
302 #(#code)*
303 }
304 };
305
306 TokenStream::from(expanded)
307}
308
309#[derive(Debug)]
310struct Tag {
311 name: Option<String>,
312 description: Option<String>,
313 required: Option<String>,
314 min: Option<(i64, String)>,
315 max: Option<(i64, String)>,
316}
317
318struct IntStrTuple {
319 int: LitInt,
320 _comma: Token![,],
321 msg: LitStr,
322}
323
324impl Parse for IntStrTuple {
325 fn parse(input: ParseStream) -> syn::Result<Self> {
326 Ok(IntStrTuple {
327 int: input.parse()?,
328 _comma: input.parse()?,
329 msg: input.parse()?,
330 })
331 }
332}
333
334#[proc_macro_derive(AFastKind, attributes(validate, afast))]
336pub fn derive_get_kind(input: TokenStream) -> TokenStream {
337 let input = parse_macro_input!(input as DeriveInput);
338 let name = &input.ident;
339 let generics = &input.generics;
340
341 let kind_impl = match generate_kind_expression(&input.data) {
342 Ok(kind_impl) => kind_impl,
343 Err(err) => return err.to_compile_error().into(),
344 };
345
346 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
347
348 let expanded = quote! {
349 impl #impl_generics AFastKind for #name #ty_generics #where_clause {
350 fn kind() -> afast::Kind {
351 #kind_impl
352 }
353
354 fn field(name: &str) -> afast::Field {
355 afast::Field { name: name.to_string(), kind: <#name as AFastKind>::kind(), tag: None }
356 }
357 }
358 };
359
360 TokenStream::from(expanded)
361}
362
363fn generate_kind_expression(data: &Data) -> Result<proc_macro2::TokenStream, syn::Error> {
365 match data {
366 Data::Struct(data_struct) => match &data_struct.fields {
367 syn::Fields::Named(fields) => {
368 let mut field_kinds = Vec::new();
369 for f in &fields.named {
370 if parse_ignore(&f.attrs)? {
371 continue;
372 }
373 let field_name = f.ident.as_ref().unwrap();
374 let field_type = &f.ty;
375 let kind_expr = type_to_kind_expr(field_type);
376 let field_tag = parse_tags(&f.attrs)?;
377 let tag_expr = generate_tag_expression(&field_tag);
378
379 field_kinds.push(quote! {
380 afast::Field { name: stringify!(#field_name).to_string(), kind: #kind_expr, tag: #tag_expr }
381 });
382 }
383
384 Ok(quote! { afast::Kind::Struct { fields: vec![#(#field_kinds),*] } })
385 }
386 syn::Fields::Unnamed(fields) => {
387 let mut field_kinds = Vec::new();
388 for (i, f) in fields.unnamed.iter().enumerate() {
389 if parse_ignore(&f.attrs)? {
390 continue;
391 }
392 let field_type = &f.ty;
393 let kind_expr = type_to_kind_expr(field_type);
394 let field_tag = parse_tags(&f.attrs)?;
395 let tag_expr = generate_tag_expression(&field_tag);
396
397 field_kinds.push(quote! {
398 afast::Field { name: format!("_{}", #i), kind: #kind_expr, tag: #tag_expr }
399 });
400 }
401 Ok(quote! { afast::Kind::Struct { fields: vec![#(#field_kinds),*] } })
402 }
403 syn::Fields::Unit => Ok(quote! { afast::Kind::Struct { fields: vec![] } }),
404 },
405 Data::Enum(data_enum) => {
406 let mut variant_kinds = Vec::new();
407 for variant in &data_enum.variants {
408 let name = &variant.ident.to_string();
409 let variant_kind = match &variant.fields {
410 syn::Fields::Unit => quote! { (afast::Kind::Unit, #name.to_string()) },
411 syn::Fields::Unnamed(fields) => {
412 let mut field_kinds = Vec::new();
413 for (i, f) in fields.unnamed.iter().enumerate() {
414 if parse_ignore(&f.attrs)? {
415 continue;
416 }
417 let field_type = &f.ty;
418 let kind_expr = type_to_kind_expr(field_type);
419 let field_tag = parse_tags(&f.attrs)?;
420 let tag_expr = generate_tag_expression(&field_tag);
421
422 field_kinds.push(quote! { afast::Field { name: format!("_{}", #i), kind: #kind_expr, tag: #tag_expr } });
423 }
424 quote! { (afast::Kind::Struct { fields: vec![#(#field_kinds),*] }, #name.to_string()) }
425 }
426 syn::Fields::Named(fields) => {
427 let mut field_kinds = Vec::new();
428 for f in &fields.named {
429 if parse_ignore(&f.attrs)? {
430 continue;
431 }
432 let field_name = f.ident.as_ref().unwrap();
433 let field_type = &f.ty;
434 let kind_expr = type_to_kind_expr(field_type);
435 let field_tag = parse_tags(&f.attrs)?;
436 let tag_expr = generate_tag_expression(&field_tag);
437
438 field_kinds.push(quote! { afast::Field { name: stringify!(#field_name).to_string(), kind: #kind_expr, tag: #tag_expr } });
439 }
440 quote! { (afast::Kind::Struct { fields: vec![#(#field_kinds),*] }, #name.to_string()) }
441 }
442 };
443 variant_kinds.push(variant_kind);
444 }
445 Ok(quote! { afast::Kind::Enum { variants: vec![#(#variant_kinds),*] } })
446 }
447 Data::Union(_) => Ok(quote! { afast::Kind::Struct { fields: vec![] } }),
448 }
449}
450
451fn generate_tag_expression(tag: &Tag) -> proc_macro2::TokenStream {
453 let name = tag
454 .name
455 .as_ref()
456 .map(|n| quote! { Some(#n.to_string()) })
457 .unwrap_or(quote! { None });
458 let description = tag
459 .description
460 .as_ref()
461 .map(|d| quote! { Some(#d.to_string()) })
462 .unwrap_or(quote! { None });
463 let required = tag
464 .required
465 .as_ref()
466 .map(|r| quote! { Some(#r.to_string()) })
467 .unwrap_or(quote! { None });
468 let min = tag
469 .min
470 .as_ref()
471 .map(|(v, msg)| quote! { Some((#v, #msg.to_string())) })
472 .unwrap_or(quote! { None });
473 let max = tag
474 .max
475 .as_ref()
476 .map(|(v, msg)| quote! { Some((#v, #msg.to_string())) })
477 .unwrap_or(quote! { None });
478
479 if tag.name.is_none()
480 && tag.description.is_none()
481 && tag.required.is_none()
482 && tag.min.is_none()
483 && tag.max.is_none()
484 {
485 quote! { None }
486 } else {
487 quote! { Some(afast::Tag { name: #name, description: #description, required: #required, min: #min, max: #max }) }
488 }
489}
490
491fn parse_tags(attrs: &Vec<Attribute>) -> Result<Tag, syn::Error> {
493 let mut tag = Tag {
494 name: None,
495 description: None,
496 required: None,
497 min: None,
498 max: None,
499 };
500 for attr in attrs {
501 if attr.path().is_ident("validate") {
502 let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
503 for meta in nested {
504 match meta {
505 Meta::List(meta) => {
506 if meta.path.is_ident("name") {
507 tag.name = Some(meta.parse_args::<LitStr>()?.value());
508 } else if meta.path.is_ident("desc") {
509 tag.description = Some(meta.parse_args::<LitStr>()?.value());
510 } else if meta.path.is_ident("required") {
511 tag.required = Some(meta.parse_args::<LitStr>()?.value());
512 } else if meta.path.is_ident("min") {
513 let inner = meta.parse_args::<IntStrTuple>()?;
514 tag.min = Some((inner.int.base10_parse::<i64>()?, inner.msg.value()));
515 } else if meta.path.is_ident("max") {
516 let inner = meta.parse_args::<IntStrTuple>()?;
517 tag.max = Some((inner.int.base10_parse::<i64>()?, inner.msg.value()));
518 } else {
519 return Err(syn::Error::new(
520 meta.path.span(),
521 format!(
522 "Unknown validate attribute: {}",
523 meta.path.get_ident().unwrap()
524 ),
525 ));
526 }
527 }
528 _ => {}
529 }
530 }
531 }
532 }
533 Ok(tag)
534}
535
536fn type_to_kind_expr(ty: &syn::Type) -> proc_macro2::TokenStream {
538 match ty {
539 syn::Type::Path(type_path) => {
540 if let Some(segment) = type_path.path.segments.last() {
541 let type_name = segment.ident.to_string();
542 if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
543 if type_name == "Option" {
544 if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
545 let inner_kind = type_to_kind_expr(inner_ty);
546 return quote! { afast::Kind::Nullable(Box::new(#inner_kind)) };
547 }
548 } else if type_name == "Vec" {
549 if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
550 let inner_kind = type_to_kind_expr(inner_ty);
551 return quote! { afast::Kind::Vec(Box::new(#inner_kind)) };
552 }
553 }
554 }
555 match type_name.as_str() {
556 "i8" => quote! { afast::Kind::I8 },
557 "i16" => quote! { afast::Kind::I16 },
558 "i32" => quote! { afast::Kind::I32 },
559 "i64" => quote! { afast::Kind::I64 },
560 "i128" => quote! { afast::Kind::I128 },
561 "u8" => quote! { afast::Kind::U8 },
562 "u16" => quote! { afast::Kind::U16 },
563 "u32" => quote! { afast::Kind::U32 },
564 "u64" => quote! { afast::Kind::U64 },
565 "u128" => quote! { afast::Kind::U128 },
566 "f32" => quote! { afast::Kind::F32 },
567 "f64" => quote! { afast::Kind::F64 },
568 "bool" => quote! { afast::Kind::Bool },
569 "String" => quote! { afast::Kind::String },
570 "str" => quote! { afast::Kind::String },
571 "()" => quote! { afast::Kind::Unit },
572 _ => quote! { <#ty as AFastKind>::kind() },
573 }
574 } else {
575 quote! { afast::Kind::String }
576 }
577 }
578 syn::Type::Tuple(type_tuple) => {
579 if type_tuple.elems.is_empty() {
580 quote! { afast::Kind::Unit }
581 } else {
582 quote! { afast::Kind::String }
583 }
584 }
585 _ => quote! { afast::Kind::String },
586 }
587}
588
589fn parse_ignore(attrs: &Vec<Attribute>) -> Result<bool, syn::Error> {
590 for attr in attrs {
591 if attr.path().is_ident("afast") {
592 let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
593 for meta in nested {
594 match meta {
595 Meta::Path(path) if path.is_ident("ignore") => return Ok(true),
596 _ => {}
597 }
598 }
599 }
600 }
601 Ok(false)
602}