educe/trait_handlers/deref_mut/
deref_mut_struct.rs1use std::str::FromStr;
2
3use proc_macro2::TokenStream;
4use quote::quote;
5use syn::{Data, DeriveInput, Meta};
6
7use super::{
8 super::TraitHandler,
9 models::{FieldAttributeBuilder, TypeAttributeBuilder},
10};
11use crate::{panic, Trait};
12
13pub struct DerefMutStructHandler;
14
15impl TraitHandler for DerefMutStructHandler {
16 fn trait_meta_handler(
17 ast: &DeriveInput,
18 tokens: &mut TokenStream,
19 traits: &[Trait],
20 meta: &Meta,
21 ) {
22 let _ = TypeAttributeBuilder {
23 enable_flag: true
24 }
25 .from_deref_mut_meta(meta);
26
27 let mut deref_mut_tokens = TokenStream::new();
28
29 if let Data::Struct(data) = &ast.data {
30 let mut counter = 0;
31
32 for (index, field) in data.fields.iter().enumerate() {
33 let field_attribute = FieldAttributeBuilder {
34 enable_flag: true
35 }
36 .from_attributes(&field.attrs, traits);
37
38 if field_attribute.flag {
39 if !deref_mut_tokens.is_empty() {
40 panic::multiple_deref_mut_fields();
41 }
42
43 let field_name = if let Some(ident) = field.ident.as_ref() {
44 ident.to_string()
45 } else {
46 format!("{}", index)
47 };
48
49 deref_mut_tokens.extend(
50 TokenStream::from_str(&format!(
51 "&mut self.{field_name}",
52 field_name = field_name
53 ))
54 .unwrap(),
55 );
56 }
57
58 counter += 1;
59 }
60
61 if deref_mut_tokens.is_empty() {
62 if counter == 1 {
63 let field = data.fields.iter().next().unwrap();
64
65 let field_name = if let Some(ident) = field.ident.as_ref() {
66 ident.to_string()
67 } else {
68 String::from("0")
69 };
70
71 deref_mut_tokens.extend(
72 TokenStream::from_str(&format!(
73 "&mut self.{field_name}",
74 field_name = field_name
75 ))
76 .unwrap(),
77 );
78 } else {
79 panic::no_deref_mut_field();
80 }
81 }
82 }
83
84 let ident = &ast.ident;
85
86 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
87
88 let deref_mut_impl = quote! {
89 impl #impl_generics core::ops::DerefMut for #ident #ty_generics #where_clause {
90 #[inline]
91 fn deref_mut(&mut self) -> &mut Self::Target {
92 #deref_mut_tokens
93 }
94 }
95 };
96
97 tokens.extend(deref_mut_impl);
98 }
99}