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