dada_util_procmacro/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use synstructure::decl_derive;
4
5mod boxed_async_fn;
6mod salsa_serialize;
7
8decl_derive!([FromImpls, attributes(no_from_impl)] => from_impls_derive);
9decl_derive!([SalsaSerialize] => salsa_serialize::salsa_serialize_derive);
10
11fn from_impls_derive(s: synstructure::Structure) -> TokenStream {
12 let result = s
13 .variants()
14 .iter()
15 .map(|variant| {
16 let variant_name = &variant.ast().ident;
17 let fields = &variant.ast().fields;
18
19 for attr in variant
20 .ast()
21 .attrs
22 .iter()
23 .filter(|a| a.meta.path().is_ident("no_from_impl"))
24 {
25 if attr.meta.require_path_only().is_err() {
26 return Err(syn::Error::new_spanned(
27 attr,
28 "`no_from_impl` does not accept arguments",
29 ));
30 }
31 }
32
33 if variant
34 .ast()
35 .attrs
36 .iter()
37 .any(|a| a.meta.path().is_ident("no_from_impl"))
38 {
39 return Ok(quote!());
40 }
41
42 if fields.len() != 1 {
43 return Err(syn::Error::new_spanned(
44 variant.ast().ident,
45 "each variant must have exactly one field",
46 ));
47 }
48
49 let field_ty = &fields.iter().next().unwrap().ty;
50 Ok(s.gen_impl(quote! {
51 gen impl From<#field_ty> for @Self {
52 fn from(value: #field_ty) -> Self {
53 Self::#variant_name(value)
54 }
55 }
56
57 }))
58 })
59 .collect::<syn::Result<proc_macro2::TokenStream>>();
60
61 match result {
62 Ok(tokens) => tokens.into(),
63 Err(err) => err.into_compile_error().into(),
64 }
65}
66
67#[proc_macro_attribute]
72pub fn boxed_async_fn(args: TokenStream, input: TokenStream) -> TokenStream {
73 boxed_async_fn::boxed_async_fn(args, input)
74}