1use proc_macro2::TokenStream as TokenStream2;
16use quote::quote;
17use syn::{
18 spanned::Spanned,
19 Field,
20 Fields,
21};
22
23pub fn ensure_non_empty_enum(
25 s: &synstructure::Structure,
26 trait_name: &str,
27) -> syn::Result<()> {
28 if s.variants().is_empty() {
29 Err(syn::Error::new(
30 s.ast().span(),
31 format!(
32 "can only derive `{trait_name}` for Rust `enum` items \
33 with at least one variant"
34 ),
35 ))
36 } else {
37 Ok(())
38 }
39}
40
41pub fn body_from_fields(
43 fields: &Fields,
44 transformer: Option<fn(TokenStream2, &Field) -> TokenStream2>,
45) -> TokenStream2 {
46 let from_params_elems = || {
47 fields.iter().enumerate().map(|(idx, field)| {
48 let idx = syn::Index::from(idx);
49 let value = match &transformer {
50 None => quote!(value.#idx),
51 Some(transformer) => transformer(quote!(value.#idx), field),
52 };
53 match &field.ident {
54 None => quote!(#value),
56 Some(ident) => {
58 quote! {
59 #ident: #value
60 }
61 }
62 }
63 })
64 };
65 match fields {
66 Fields::Named(_) => {
68 let self_fields = from_params_elems();
69 quote!(
70 {
71 #( #self_fields, )*
72 }
73 )
74 }
75 Fields::Unnamed(_) => {
77 let self_elems = from_params_elems();
78 quote! {
79 ( #( #self_elems, )* )
80 }
81 }
82 Fields::Unit => quote!(),
84 }
85}
86
87pub fn tuple_elems_from_fields(
89 fields: &Fields,
90 transformer: Option<fn(TokenStream2, &Field) -> TokenStream2>,
91) -> TokenStream2 {
92 let elems = fields.iter().enumerate().map(|(idx, field)| {
93 let accessor = field
95 .ident
96 .as_ref()
97 .map(|ident| quote!(#ident))
98 .unwrap_or_else(|| {
99 let idx = syn::Index::from(idx);
100 quote!(#idx)
101 });
102 match &transformer {
103 None => quote!(&self.#accessor),
104 Some(transformer) => transformer(quote!(&self.#accessor), field),
105 }
106 });
107 quote! {
108 ( #( #elems, )* )
109 }
110}