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 ty: Path,
29 #[darling(default)]
31 field: Option<Ident>,
32 #[darling(default)]
34 method: Option<Ident>,
35 #[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 #[darling(default)]
48 no_std: Flag,
49
50 #[darling(default)]
52 into: bool,
53
54 #[darling(default)]
56 strip_option: bool,
57
58 #[darling(default)]
60 borrow_self: bool,
61
62 #[darling(default)]
64 bool: bool,
65
66 #[darling(default)]
69 generate: Option<bool>,
70
71 #[darling(default)]
73 generate_public: Option<bool>,
74
75 #[darling(default)]
77 generate_private: Option<bool>,
78
79 #[darling(default)]
81 prefix: Option<String>,
82
83 #[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 #[darling(default)]
96 rename: Option<Ident>,
97
98 #[darling(default)]
100 into: Option<bool>,
101
102 #[darling(default)]
104 strip_option: Option<bool>,
105
106 #[darling(default)]
108 borrow_self: Option<bool>,
109
110 #[darling(default)]
112 bool: Option<bool>,
113
114 #[darling(default)]
116 generate: bool,
117
118 #[darling(default)]
120 skip: bool,
121
122 #[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 let darling_attrs: FieldAttrs = match FromField::from_field(field) {
192 Ok(v) => v,
193 Err(e) => return Err(e.write_errors()),
194 };
195
196 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 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 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 let value_ty = if def.uses_into {
265 quote! { impl ::#std::convert::Into<#field_ty> }
266 } else {
267 quote! { #field_ty }
268 };
269
270 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 let params = if def.bool {
278 SynTokenStream::new()
279 } else {
280 quote! { value: #value_ty }
281 };
282
283 let field_attrs = if def.must_use {
285 SynTokenStream::new()
286 } else {
287 quote! { #[must_use] }
288 };
289
290 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}