1 | #![cfg_attr (feature = "nightly" , feature(proc_macro_diagnostic))] |
2 | |
3 | extern crate proc_macro; |
4 | |
5 | use darling::*; |
6 | use darling::util::Flag; |
7 | use proc_macro::TokenStream; |
8 | use proc_macro2::{Span, TokenStream as SynTokenStream}; |
9 | use std::result::Result; |
10 | use syn::*; |
11 | use syn::spanned::Spanned; |
12 | use quote::*; |
13 | |
14 | #[cfg (feature = "nightly" )] |
15 | fn error(span: Span, data: &str) -> SynTokenStream { |
16 | span.unstable().error(data).emit(); |
17 | SynTokenStream::new() |
18 | } |
19 | |
20 | #[cfg (not(feature = "nightly" ))] |
21 | fn error(_: Span, data: &str) -> SynTokenStream { |
22 | quote! { compile_error!(#data); } |
23 | } |
24 | |
25 | #[derive (Debug, Clone, FromMeta)] |
26 | struct ExternalDelegate { |
27 | /// The type to generate a delegate for. |
28 | ty: Path, |
29 | /// The field to delegate the methods to. |
30 | #[darling(default)] |
31 | field: Option<Ident>, |
32 | /// The method to delegate the methods to. |
33 | #[darling(default)] |
34 | method: Option<Ident>, |
35 | } |
36 | |
37 | #[derive (Debug, Clone, FromDeriveInput)] |
38 | #[darling(attributes(setters), supports(struct_named))] |
39 | struct ContainerAttrs { |
40 | ident: Ident, |
41 | generics: Generics, |
42 | |
43 | /// Use the core library rather than the std library. |
44 | #[darling(default)] |
45 | no_std: Flag, |
46 | |
47 | /// Whether to accept any field that converts via `Into` by default. |
48 | #[darling(default)] |
49 | into: bool, |
50 | |
51 | /// Whether to strip `Option<T>` into `T` in the parameters for the setter method by default. |
52 | #[darling(default)] |
53 | strip_option: bool, |
54 | |
55 | /// Whether to borrow or take ownership of `self` in the setter method by default. |
56 | #[darling(default)] |
57 | borrow_self: bool, |
58 | |
59 | /// Whether to generate a method that sets a boolean by default. |
60 | #[darling(default)] |
61 | bool: bool, |
62 | |
63 | /// Whether to generate setters for this struct's fields by default. If set to false, |
64 | /// `generate_public` and `generate_private` are ignored. |
65 | #[darling(default)] |
66 | generate: Option<bool>, |
67 | |
68 | /// Whether to generate setters for this struct's public fields by default. |
69 | #[darling(default)] |
70 | generate_public: Option<bool>, |
71 | |
72 | /// Whether to generate setters for this struct's private fields by default. |
73 | #[darling(default)] |
74 | generate_private: Option<bool>, |
75 | |
76 | /// A prefix for the generated setter methods. |
77 | #[darling(default)] |
78 | prefix: Option<String>, |
79 | |
80 | /// Other types to generate delegates to this type for. Note that this does not support |
81 | /// generics. |
82 | #[darling(multiple)] |
83 | generate_delegates: Vec<ExternalDelegate>, |
84 | } |
85 | |
86 | #[derive (Debug, Clone, FromField)] |
87 | #[darling(attributes(setters), forward_attrs(doc))] |
88 | struct FieldAttrs { |
89 | attrs: Vec<Attribute>, |
90 | |
91 | /// The name of the generated setter method. |
92 | #[darling(default)] |
93 | rename: Option<Ident>, |
94 | |
95 | /// Whether to accept any field that converts via `Into` to this field's type. |
96 | #[darling(default)] |
97 | into: Option<bool>, |
98 | |
99 | /// Whether to strip `Option<T>` into `T` in the parameters for the setter method. |
100 | #[darling(default)] |
101 | strip_option: Option<bool>, |
102 | |
103 | /// Whether to borrow or take ownership of `self` for the setter method. |
104 | #[darling(default)] |
105 | borrow_self: Option<bool>, |
106 | |
107 | /// Whether to generate a method that sets a boolean. |
108 | #[darling(default)] |
109 | bool: Option<bool>, |
110 | |
111 | /// Whether to generate a setter for this field regardless of global settings. |
112 | #[darling(default)] |
113 | generate: bool, |
114 | |
115 | /// Whether to skip this field regardless of global settings. Overwrites `generate`. |
116 | #[darling(default)] |
117 | skip: bool, |
118 | } |
119 | |
120 | struct ContainerDef { |
121 | name: Ident, |
122 | ty: Type, |
123 | std: Ident, |
124 | generics: Generics, |
125 | |
126 | prefix: String, |
127 | uses_into: bool, |
128 | strip_option: bool, |
129 | borrow_self: bool, |
130 | bool: bool, |
131 | generate_public: bool, |
132 | generate_private: bool, |
133 | |
134 | generate_delegates: Vec<ExternalDelegate>, |
135 | } |
136 | |
137 | struct FieldDef { |
138 | field_name: Ident, |
139 | field_ty: Type, |
140 | field_doc: SynTokenStream, |
141 | setter_name: Ident, |
142 | uses_into: bool, |
143 | strip_option: bool, |
144 | borrow_self: bool, |
145 | bool: bool, |
146 | } |
147 | |
148 | fn init_container_def(input: &DeriveInput) -> Result<ContainerDef, SynTokenStream> { |
149 | let darling_attrs: ContainerAttrs = match FromDeriveInput::from_derive_input(input) { |
150 | Ok(v) => v, |
151 | Err(e) => return Err(e.write_errors()), |
152 | }; |
153 | |
154 | let ident = &darling_attrs.ident; |
155 | let (_, generics_ty, _) = darling_attrs.generics.split_for_impl(); |
156 | let ty = quote! { #ident #generics_ty }; |
157 | |
158 | let generate = darling_attrs.generate.unwrap_or(true); |
159 | Ok(ContainerDef { |
160 | name: darling_attrs.ident, |
161 | ty: parse2(ty).expect("Internal error: failed to parse internally generated type." ), |
162 | std: if darling_attrs.no_std.is_present() { |
163 | Ident::new("core" , Span::call_site()) |
164 | } else { |
165 | Ident::new("std" , Span::call_site()) |
166 | }, |
167 | borrow_self: darling_attrs.borrow_self, |
168 | generics: darling_attrs.generics, |
169 | prefix: darling_attrs.prefix.unwrap_or(String::new()), |
170 | uses_into: darling_attrs.into, |
171 | strip_option: darling_attrs.strip_option, |
172 | bool: darling_attrs.bool, |
173 | generate_public: generate && darling_attrs.generate_public.unwrap_or(true), |
174 | generate_private: generate && darling_attrs.generate_private.unwrap_or(true), |
175 | generate_delegates: darling_attrs.generate_delegates, |
176 | }) |
177 | } |
178 | |
179 | fn init_field_def( |
180 | container: &ContainerDef, field: &Field, |
181 | ) -> Result<Option<FieldDef>, SynTokenStream> { |
182 | // Decode the various attribute options. |
183 | let darling_attrs: FieldAttrs = match FromField::from_field(field) { |
184 | Ok(v) => v, |
185 | Err(e) => return Err(e.write_errors()), |
186 | }; |
187 | |
188 | // Check whether this field should generate a setter. |
189 | if darling_attrs.skip { return Ok(None) } |
190 | let generates = match field.vis { |
191 | Visibility::Public(_) => container.generate_public, |
192 | _ => container.generate_private, |
193 | }; |
194 | if !(darling_attrs.generate || generates) { return Ok(None) } |
195 | |
196 | // Returns a definition for this field. |
197 | let ident = match &field.ident { |
198 | Some(i) => i.clone(), |
199 | None => panic!("Internal error: init_field_def on wrong item." ), |
200 | }; |
201 | Ok(Some(FieldDef { |
202 | field_name: ident.clone(), |
203 | field_ty: field.ty.clone(), |
204 | field_doc: if let Visibility::Public(_) = field.vis { |
205 | let doc_str = |
206 | format!("Sets the [` {}`](#structfield. {}) field of this struct." , ident, ident); |
207 | quote! { #[doc = #doc_str] } |
208 | } else { |
209 | let attrs = darling_attrs.attrs; |
210 | quote! { #( #attrs )* } |
211 | }, |
212 | setter_name: darling_attrs.rename.unwrap_or_else(|| |
213 | Ident::new(&format!(" {}{}" , container.prefix, ident), ident.span()) |
214 | ), |
215 | uses_into: darling_attrs.into.unwrap_or(container.uses_into), |
216 | strip_option: darling_attrs.strip_option.unwrap_or(container.strip_option), |
217 | borrow_self: darling_attrs.borrow_self.unwrap_or(container.borrow_self), |
218 | bool: darling_attrs.bool.unwrap_or(container.bool), |
219 | })) |
220 | } |
221 | |
222 | |
223 | fn generate_setter_method( |
224 | container: &ContainerDef, def: FieldDef, delegate_toks: &Option<SynTokenStream>, |
225 | ) -> Result<SynTokenStream, SynTokenStream> { |
226 | let FieldDef { |
227 | field_name, mut field_ty, field_doc, setter_name, .. |
228 | } = def; |
229 | let std = &container.std; |
230 | |
231 | // Strips `Option<T>` into `T` if the `strip_option` property is set. |
232 | let mut stripped_option = false; |
233 | if def.strip_option { |
234 | if let Type::Path(path) = &field_ty { |
235 | let segment = path.path.segments.last().unwrap(); |
236 | if segment.ident.to_string() == "Option" { |
237 | if let PathArguments::AngleBracketed(path) = &segment.arguments { |
238 | if let GenericArgument::Type(tp) = path.args.first().unwrap() { |
239 | field_ty = tp.clone(); |
240 | stripped_option = true; |
241 | } |
242 | } |
243 | } |
244 | } |
245 | } |
246 | |
247 | // The type the setter accepts. |
248 | let value_ty = if def.uses_into { |
249 | quote! { impl ::#std::convert::Into<#field_ty> } |
250 | } else { |
251 | quote! { #field_ty } |
252 | }; |
253 | |
254 | // The expression actually stored into the field. |
255 | let mut expr = quote! { value }; |
256 | if def.uses_into { expr = quote! { #expr.into() }; } |
257 | if def.bool { expr = quote! { true }; } |
258 | if stripped_option { expr = quote! { Some(#expr) }; } |
259 | |
260 | // Handle the parameters when bool is enabled. |
261 | let params = if def.bool { |
262 | SynTokenStream::new() |
263 | } else { |
264 | quote! { value: #value_ty } |
265 | }; |
266 | |
267 | // Generates the setter method itself. |
268 | let container_name = &container.name; |
269 | if let Some(delegate) = delegate_toks { |
270 | let _self = if def.borrow_self { |
271 | quote! { &mut self } |
272 | } else { |
273 | quote! { mut self } |
274 | }; |
275 | |
276 | let return_self = if def.borrow_self { |
277 | quote! { &mut Self } |
278 | } else { |
279 | quote! { Self } |
280 | }; |
281 | |
282 | Ok(quote! { |
283 | #field_doc |
284 | pub fn #setter_name (#_self, #params) -> #return_self { |
285 | self.#delegate.#field_name = #expr; |
286 | self |
287 | } |
288 | }) |
289 | } else { |
290 | if def.borrow_self { |
291 | Ok(quote! { |
292 | #field_doc |
293 | pub fn #setter_name (&mut self, #params) -> &mut Self { |
294 | self.#field_name = #expr; |
295 | self |
296 | } |
297 | }) |
298 | } else { |
299 | Ok(quote! { |
300 | #field_doc |
301 | pub fn #setter_name (self, #params) -> Self { |
302 | #container_name { #field_name: #expr, ..self } |
303 | } |
304 | }) |
305 | } |
306 | } |
307 | } |
308 | |
309 | fn generate_setters_for( |
310 | input: &DeriveInput, data: &DataStruct, generics: &Generics, |
311 | ty: SynTokenStream, delegate_toks: Option<SynTokenStream>, |
312 | ) -> Result<SynTokenStream, SynTokenStream> { |
313 | let container_def: ContainerDef = init_container_def(&input)?; |
314 | let mut toks: TokenStream = SynTokenStream::new(); |
315 | for field: &Field in &data.fields { |
316 | if let Some(field_def: FieldDef) = init_field_def(&container_def, field)? { |
317 | let method: TokenStream = generate_setter_method(&container_def, field_def, &delegate_toks)?; |
318 | toks.extend(iter:method); |
319 | } |
320 | } |
321 | |
322 | let (generics_bound: ImplGenerics<'_>, _, generics_where: Option<&WhereClause>) = generics.split_for_impl(); |
323 | Ok(quote! { |
324 | impl #generics_bound #ty #generics_where { |
325 | #toks |
326 | } |
327 | }) |
328 | |
329 | } |
330 | |
331 | fn generate_setters(input: &DeriveInput, data: &DataStruct) -> Result<TokenStream, TokenStream> { |
332 | let container_def = init_container_def(&input)?; |
333 | let mut toks = SynTokenStream::new(); |
334 | let container_ty = &container_def.ty; |
335 | toks.extend(generate_setters_for( |
336 | input, data, &container_def.generics, quote! { #container_ty }, None, |
337 | )); |
338 | for delegate in container_def.generate_delegates { |
339 | let delegate_ty = delegate.ty; |
340 | toks.extend(generate_setters_for( |
341 | input, data, &Generics::default(), quote! { #delegate_ty }, |
342 | if delegate.field.is_some() && delegate.method.is_some() { |
343 | return Err(error(input.span(), |
344 | "Cannot set both `method` and `field` on a delegate." ).into()); |
345 | } else if let Some(field) = &delegate.field { |
346 | Some(quote! { #field }) |
347 | } else if let Some(method) = &delegate.method { |
348 | Some(quote! { #method() }) |
349 | } else { |
350 | return Err(error(input.span(), |
351 | "Must set either `method` or `field` on a delegate." ).into()); |
352 | } |
353 | )); |
354 | } |
355 | Ok(toks.into()) |
356 | } |
357 | |
358 | #[proc_macro_derive (Setters, attributes(setters))] |
359 | pub fn derive_setters(input: TokenStream) -> TokenStream { |
360 | let input: DeriveInput = parse_macro_input!(input); |
361 | if let Data::Struct(data: &DataStruct) = &input.data { |
362 | match generate_setters(&input, data) { |
363 | Ok(toks: TokenStream) => toks, |
364 | Err(toks: TokenStream) => toks, |
365 | } |
366 | } else { |
367 | error(input.span(), data:"`#[derive(Setters)] may only be used on structs." ).into() |
368 | } |
369 | } |
370 | |