derive_tools_meta/derive/
deref_mut.rs1use macro_tools ::
2{
3 diag, struct_like ::StructLike, Result, qt, attr, syn, proc_macro2, return_syn_err, syn_err, Spanned,
4};
5
6pub fn deref_mut(input: proc_macro ::TokenStream) -> Result< proc_macro2 ::TokenStream >
14{
15 let original_input = input.clone();
16 let parsed = syn ::parse :: < StructLike >(input)?;
17 let has_debug = attr ::has_debug(parsed.attrs().iter())?;
18 let item_name = &parsed.ident();
19
20 let (generics_impl, generics_ty, generics_where_option) = parsed.generics().split_for_impl();
21
22 let result = match parsed
23 {
24 StructLike ::Unit(ref _item) =>
25 {
26 return_syn_err!(parsed.span(), "Expects a structure with one field");
27 }
28 StructLike ::Struct(ref item) =>
29 {
30 let fields_count = item.fields.len();
31 let mut target_field_type = None;
32 let mut target_field_name = None;
33 let mut deref_mut_attr_count = 0;
34
35 if fields_count == 0
36 {
37 return_syn_err!(item.span(), "DerefMut cannot be derived for structs with no fields.");
38 } else if fields_count == 1
39 {
40 let field = item.fields.iter().next().expect("Expects a single field to derive DerefMut");
42 target_field_type = Some(field.ty.clone());
43 target_field_name.clone_from(&field.ident);
44 } else {
45 for field in &item.fields
47 {
48 if attr ::has_deref_mut(field.attrs.iter())?
49 {
50 deref_mut_attr_count += 1;
51 target_field_type = Some(field.ty.clone());
52 target_field_name.clone_from(&field.ident);
53 }
54 }
55
56 if deref_mut_attr_count == 0
57 {
58 return_syn_err!(
59 item.span(),
60 "DerefMut cannot be derived for multi-field structs without a `#[ deref_mut ]` attribute on one field."
61 );
62 } else if deref_mut_attr_count > 1
63 {
64 return_syn_err!(item.span(), "Only one field can have the `#[ deref_mut ]` attribute.");
65 }
66 }
67
68 let field_type =
69 target_field_type.ok_or_else(|| syn_err!(item.span(), "Could not determine target field type for DerefMut."))?;
70 let field_name = target_field_name;
71
72 generate(
73 item_name,
74 &generics_impl,
75 &generics_ty,
76 generics_where_option,
77 &field_type,
78 field_name.as_ref(),
79 )
80 }
81 StructLike ::Enum(ref item) =>
82 {
83 return_syn_err!(
84 item.span(),
85 "DerefMut cannot be derived for enums. It is only applicable to structs with a single field."
86 );
87 }
88 };
89
90 if has_debug
91 {
92 let about = format!("derive: DerefMut\nstructure: {item_name}");
93 diag ::report_print(about, &original_input, &result);
94 }
95
96 Ok(result)
97}
98
99fn generate(
116 item_name: &syn ::Ident,
117 generics_impl: &syn ::ImplGenerics< '_ >,
118 generics_ty: &syn ::TypeGenerics< '_ >,
119 generics_where_option: Option< &syn ::WhereClause >,
120 field_type: &syn ::Type,
121 field_name: Option< &syn ::Ident >,
122) -> proc_macro2 ::TokenStream {
123 let body = if let Some(field_name) = field_name
124 {
125 qt! { &mut self.#field_name }
126 } else {
127 qt! { &mut self.0 }
128 };
129
130 qt! {
131 #[ automatically_derived ]
132 impl #generics_impl ::core ::ops ::DerefMut for #item_name #generics_ty
133 #generics_where_option
134 {
135 fn deref_mut( &mut self ) -> &mut #field_type
136 {
137 #body
138 }
139 }
140 }
141}