educe/trait_handlers/deref_mut/
deref_mut_struct.rs

1use 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}