derive_setters/
lib.rs

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