1#![cfg_attr(feature = "nightly", feature(proc_macro_diagnostic))]
2
3extern crate proc_macro;
4
5use darling::*;
6use darling::util::Flag;
7use proc_macro::TokenStream;
8use proc_macro2::{Span, TokenStream as SynTokenStream};
9use std::result::Result;
10use syn::*;
11use syn::spanned::Spanned;
12use quote::*;
13
14#[cfg(feature = "nightly")]
15fn error(span: Span, data: &str) -> SynTokenStream {
16 span.unstable().error(data).emit();
17 SynTokenStream::new()
18}
19
20#[cfg(not(feature = "nightly"))]
21fn error(_: Span, data: &str) -> SynTokenStream {
22 quote! { compile_error!(#data); }
23}
24
25#[derive(Debug, Clone, FromMeta)]
26struct 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))]
39struct 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))]
88struct 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
120struct 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
137struct 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
148fn 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
179fn 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
223fn 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
309fn 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
331fn 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))]
359pub 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