educe/trait_handlers/deref/
deref_enum.rs1use quote::{format_ident, quote};
2use syn::{spanned::Spanned, Data, DeriveInput, Field, Fields, Ident, Meta, Type};
3
4use super::{
5 models::{FieldAttributeBuilder, TypeAttributeBuilder},
6 TraitHandler,
7};
8use crate::{common::r#type::dereference, panic, supported_traits::Trait};
9
10pub(crate) struct DerefEnumHandler;
11
12impl TraitHandler for DerefEnumHandler {
13 #[inline]
14 fn trait_meta_handler(
15 ast: &DeriveInput,
16 token_stream: &mut proc_macro2::TokenStream,
17 traits: &[Trait],
18 meta: &Meta,
19 ) -> syn::Result<()> {
20 let _ = TypeAttributeBuilder {
21 enable_flag: true
22 }
23 .build_from_deref_meta(meta)?;
24
25 let mut target_token_stream = proc_macro2::TokenStream::new();
26 let mut arms_token_stream = proc_macro2::TokenStream::new();
27
28 if let Data::Enum(data) = &ast.data {
29 type Variants<'a> = Vec<(&'a Ident, bool, usize, Ident, &'a Type)>;
30
31 let mut variants: Variants = Vec::new();
32
33 for variant in data.variants.iter() {
34 let _ = TypeAttributeBuilder {
35 enable_flag: false
36 }
37 .build_from_attributes(&variant.attrs, traits)?;
38
39 if let Fields::Unit = &variant.fields {
40 return Err(panic::trait_not_support_unit_variant(
41 meta.path().get_ident().unwrap(),
42 variant,
43 ));
44 }
45
46 let fields = &variant.fields;
47
48 let (index, field) = if fields.len() == 1 {
49 let field = fields.into_iter().next().unwrap();
50
51 let _ = FieldAttributeBuilder {
52 enable_flag: true
53 }
54 .build_from_attributes(&field.attrs, traits)?;
55
56 (0usize, field)
57 } else {
58 let mut deref_field: Option<(usize, &Field)> = None;
59
60 for (index, field) in variant.fields.iter().enumerate() {
61 let field_attribute = FieldAttributeBuilder {
62 enable_flag: true
63 }
64 .build_from_attributes(&field.attrs, traits)?;
65
66 if field_attribute.flag {
67 if deref_field.is_some() {
68 return Err(super::panic::multiple_deref_fields_of_variant(
69 field_attribute.span,
70 variant,
71 ));
72 }
73
74 deref_field = Some((index, field));
75 }
76 }
77
78 if let Some(deref_field) = deref_field {
79 deref_field
80 } else {
81 return Err(super::panic::no_deref_field_of_variant(meta.span(), variant));
82 }
83 };
84
85 let (field_name, is_tuple): (Ident, bool) = match field.ident.as_ref() {
86 Some(ident) => (ident.clone(), false),
87 None => (format_ident!("_{}", index), true),
88 };
89
90 variants.push((&variant.ident, is_tuple, index, field_name, &field.ty));
91 }
92
93 if variants.is_empty() {
94 return Err(super::panic::no_deref_field(meta.span()));
95 }
96
97 let ty = variants[0].4;
98 let dereference_ty = dereference(ty);
99
100 target_token_stream.extend(quote!(#dereference_ty));
101
102 for (variant_ident, is_tuple, index, field_name, _) in variants {
103 let mut pattern_token_stream = proc_macro2::TokenStream::new();
104
105 if is_tuple {
106 for _ in 0..index {
107 pattern_token_stream.extend(quote!(_,));
108 }
109
110 pattern_token_stream.extend(quote!( #field_name, .. ));
111
112 arms_token_stream.extend(
113 quote!( Self::#variant_ident ( #pattern_token_stream ) => #field_name, ),
114 );
115 } else {
116 pattern_token_stream.extend(quote!( #field_name, .. ));
117
118 arms_token_stream.extend(
119 quote!( Self::#variant_ident { #pattern_token_stream } => #field_name, ),
120 );
121 }
122 }
123 }
124
125 let ident = &ast.ident;
126
127 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
128
129 token_stream.extend(quote! {
130 impl #impl_generics ::core::ops::Deref for #ident #ty_generics #where_clause {
131 type Target = #target_token_stream;
132
133 #[inline]
134 fn deref(&self) -> &Self::Target {
135 match self {
136 #arms_token_stream
137 }
138 }
139 }
140 });
141
142 Ok(())
143 }
144}