bones_utils_macros/
lib.rs1use proc_macro::TokenStream;
2use quote::{format_ident, quote, quote_spanned, spanned::Spanned};
3
4macro_rules! throw {
6 ($hasSpan:expr, $err:literal) => {
7 let span = $hasSpan.__span();
8 return quote_spanned!(span =>
9 compile_error!($err);
10 ).into();
11 };
12}
13
14fn is_simple_named_attr(attr: &venial::Attribute, name: &str) -> bool {
17 attr.get_single_path_segment() == Some(&format_ident!("{name}"))
18 && attr.get_value_tokens().is_empty()
19}
20
21#[proc_macro_derive(Deref, attributes(deref))]
23pub fn derive_deref(input: TokenStream) -> TokenStream {
24 let input = venial::parse_declaration(input.into()).unwrap();
25
26 if let Some(s) = input.as_struct() {
27 let name = &s.name;
28 let params = &s.generic_params;
29
30 match &s.fields {
31 venial::StructFields::Tuple(tuple) => {
32 if tuple.fields.len() != 1 {
33 throw!(tuple, "May only derive Deref for structs with one field.");
34 }
35
36 let deref_type = &tuple.fields[0].0.ty;
37
38 quote! {
39 impl #params ::std::ops::Deref for #name #params {
40 type Target = #deref_type;
41
42 fn deref(&self) -> &Self::Target {
43 &self.0
44 }
45 }
46 }
47 .into()
48 }
49 venial::StructFields::Named(named) => {
50 let (deref_type, field_name) = if named.fields.is_empty() {
51 throw!(named, "May not derive Deref for struct without fields");
52 } else if named.fields.len() > 1 {
53 let mut info = None;
54 for (field, _) in named.fields.iter() {
55 for attr in &field.attributes {
56 if is_simple_named_attr(attr, "deref") {
57 if info.is_some() {
58 throw!(attr, "Only one field may have the #[deref] attribute");
59 } else {
60 info = Some((&field.ty, &field.name));
61 }
62 }
63 }
64 }
65
66 if let Some(info) = info {
67 info
68 } else {
69 throw!(
70 named,
71 "One field must be annotated with a #[deref] attribute"
72 );
73 }
74 } else {
75 (&named.fields[0].0.ty, &named.fields[0].0.name)
76 };
77
78 quote! {
79 impl #params ::std::ops::Deref for #name #params {
80 type Target = #deref_type;
81
82 fn deref(&self) -> &Self::Target {
83 &self.#field_name
84 }
85 }
86 }
87 .into()
88 }
89 venial::StructFields::Unit => {
90 throw!(s, "Cannot derive Deref on anything but structs.");
91 }
92 }
93 } else {
94 throw!(input, "Cannot derive Deref on anything but structs.");
95 }
96}
97
98#[proc_macro_derive(DerefMut, attributes(deref))]
100pub fn derive_deref_mut(input: TokenStream) -> TokenStream {
101 let input = venial::parse_declaration(input.into()).unwrap();
102
103 if let Some(s) = input.as_struct() {
104 let name = &s.name;
105 let params = &s.generic_params;
106
107 match &s.fields {
108 venial::StructFields::Tuple(tuple) => {
109 if tuple.fields.len() != 1 {
110 throw!(
111 tuple,
112 "May only derive DerefMut for structs with one field."
113 );
114 }
115
116 quote! {
117 impl #params std::ops::DerefMut for #name #params {
118 fn deref_mut(&mut self) -> &mut Self::Target {
119 &mut self.0
120 }
121 }
122 }
123 .into()
124 }
125 venial::StructFields::Named(named) => {
126 let field_name = if named.fields.is_empty() {
127 throw!(named, "May not derive Deref for struct without fields");
128 } else if named.fields.len() > 1 {
129 let mut info = None;
130 for (field, _) in named.fields.iter() {
131 for attr in &field.attributes {
132 if is_simple_named_attr(attr, "deref") {
133 if info.is_some() {
134 throw!(attr, "Only one field may have the #[deref] attribute");
135 } else {
136 info = Some(&field.name);
137 }
138 }
139 }
140 }
141
142 if let Some(name) = info {
143 name
144 } else {
145 throw!(
146 named,
147 "One field must be annotated with a #[deref] attribute"
148 );
149 }
150 } else {
151 &named.fields[0].0.name
152 };
153
154 quote! {
155 impl #params std::ops::DerefMut for #name #params {
156 fn deref_mut(&mut self) -> &mut Self::Target {
157 &mut self.#field_name
158 }
159 }
160 }
161 .into()
162 }
163 venial::StructFields::Unit => {
164 throw!(s, "Cannot derive DerefMut on anything but structs.");
165 }
166 }
167 } else {
168 throw!(input, "Cannot derive DerefMut on anything but structs.");
169 }
170}