1 use std::{slice, vec};
2 
3 use proc_macro2::{Span, TokenStream};
4 use quote::ToTokens;
5 use syn::spanned::Spanned;
6 
7 use usage::{
8     self, IdentRefSet, IdentSet, LifetimeRefSet, LifetimeSet, UsesLifetimes, UsesTypeParams,
9 };
10 use {Error, FromField, FromVariant, Result};
11 
12 /// A struct or enum body.
13 ///
14 /// `V` is the type which receives any encountered variants, and `F` receives struct fields.
15 #[derive(Debug, Clone, PartialEq, Eq)]
16 pub enum Data<V, F> {
17     Enum(Vec<V>),
18     Struct(Fields<F>),
19 }
20 
21 impl<V, F> Data<V, F> {
22     /// Creates an empty body of the same shape as the passed-in body.
23     ///
24     /// # Panics
25     /// This function will panic if passed `syn::Data::Union`.
empty_from(src: &syn::Data) -> Self26     pub fn empty_from(src: &syn::Data) -> Self {
27         match *src {
28             syn::Data::Enum(_) => Data::Enum(vec![]),
29             syn::Data::Struct(ref vd) => Data::Struct(Fields::empty_from(&vd.fields)),
30             syn::Data::Union(_) => panic!("Unions are not supported"),
31         }
32     }
33 
34     /// Creates an empty body of the same shape as the passed-in body.
35     ///
36     /// `darling` does not support unions; calling this function with a union body will return an error.
try_empty_from(src: &syn::Data) -> Result<Self>37     pub fn try_empty_from(src: &syn::Data) -> Result<Self> {
38         match *src {
39             syn::Data::Enum(_) => Ok(Data::Enum(vec![])),
40             syn::Data::Struct(ref vd) => Ok(Data::Struct(Fields::empty_from(&vd.fields))),
41             // This deliberately doesn't set a span on the error message, as the error is most useful if
42             // applied to the call site of the offending macro. Given that the message is very generic,
43             // putting it on the union keyword ends up being confusing.
44             syn::Data::Union(_) => Err(Error::custom("Unions are not supported")),
45         }
46     }
47 
48     /// Creates a new `Data<&'a V, &'a F>` instance from `Data<V, F>`.
as_ref<'a>(&'a self) -> Data<&'a V, &'a F>49     pub fn as_ref<'a>(&'a self) -> Data<&'a V, &'a F> {
50         match *self {
51             Data::Enum(ref variants) => Data::Enum(variants.iter().collect()),
52             Data::Struct(ref data) => Data::Struct(data.as_ref()),
53         }
54     }
55 
56     /// Applies a function `V -> U` on enum variants, if this is an enum.
map_enum_variants<T, U>(self, map: T) -> Data<U, F> where T: FnMut(V) -> U,57     pub fn map_enum_variants<T, U>(self, map: T) -> Data<U, F>
58     where
59         T: FnMut(V) -> U,
60     {
61         match self {
62             Data::Enum(v) => Data::Enum(v.into_iter().map(map).collect()),
63             Data::Struct(f) => Data::Struct(f),
64         }
65     }
66 
67     /// Applies a function `F -> U` on struct fields, if this is a struct.
map_struct_fields<T, U>(self, map: T) -> Data<V, U> where T: FnMut(F) -> U,68     pub fn map_struct_fields<T, U>(self, map: T) -> Data<V, U>
69     where
70         T: FnMut(F) -> U,
71     {
72         match self {
73             Data::Enum(v) => Data::Enum(v),
74             Data::Struct(f) => Data::Struct(f.map(map)),
75         }
76     }
77 
78     /// Applies a function to the `Fields` if this is a struct.
map_struct<T, U>(self, mut map: T) -> Data<V, U> where T: FnMut(Fields<F>) -> Fields<U>,79     pub fn map_struct<T, U>(self, mut map: T) -> Data<V, U>
80     where
81         T: FnMut(Fields<F>) -> Fields<U>,
82     {
83         match self {
84             Data::Enum(v) => Data::Enum(v),
85             Data::Struct(f) => Data::Struct(map(f)),
86         }
87     }
88 
89     /// Consumes the `Data`, returning `Fields<F>` if it was a struct.
take_struct(self) -> Option<Fields<F>>90     pub fn take_struct(self) -> Option<Fields<F>> {
91         match self {
92             Data::Enum(_) => None,
93             Data::Struct(f) => Some(f),
94         }
95     }
96 
97     /// Consumes the `Data`, returning `Vec<V>` if it was an enum.
take_enum(self) -> Option<Vec<V>>98     pub fn take_enum(self) -> Option<Vec<V>> {
99         match self {
100             Data::Enum(v) => Some(v),
101             Data::Struct(_) => None,
102         }
103     }
104 
105     /// Returns `true` if this instance is `Data::Enum`.
is_enum(&self) -> bool106     pub fn is_enum(&self) -> bool {
107         match *self {
108             Data::Enum(_) => true,
109             Data::Struct(_) => false,
110         }
111     }
112 
113     /// Returns `true` if this instance is `Data::Struct`.
is_struct(&self) -> bool114     pub fn is_struct(&self) -> bool {
115         !self.is_enum()
116     }
117 }
118 
119 impl<V: FromVariant, F: FromField> Data<V, F> {
120     /// Attempt to convert from a `syn::Data` instance.
try_from(body: &syn::Data) -> Result<Self>121     pub fn try_from(body: &syn::Data) -> Result<Self> {
122         match *body {
123             syn::Data::Enum(ref data) => {
124                 let mut items = Vec::with_capacity(data.variants.len());
125                 let mut errors = Vec::new();
126                 for v_result in data.variants.iter().map(FromVariant::from_variant) {
127                     match v_result {
128                         Ok(val) => items.push(val),
129                         Err(err) => errors.push(err),
130                     }
131                 }
132 
133                 if !errors.is_empty() {
134                     Err(Error::multiple(errors))
135                 } else {
136                     Ok(Data::Enum(items))
137                 }
138             }
139             syn::Data::Struct(ref data) => Ok(Data::Struct(Fields::try_from(&data.fields)?)),
140             // This deliberately doesn't set a span on the error message, as the error is most useful if
141             // applied to the call site of the offending macro. Given that the message is very generic,
142             // putting it on the union keyword ends up being confusing.
143             syn::Data::Union(_) => Err(Error::custom("Unions are not supported")),
144         }
145     }
146 }
147 
148 impl<V: UsesTypeParams, F: UsesTypeParams> UsesTypeParams for Data<V, F> {
uses_type_params<'a>( &self, options: &usage::Options, type_set: &'a IdentSet, ) -> IdentRefSet<'a>149     fn uses_type_params<'a>(
150         &self,
151         options: &usage::Options,
152         type_set: &'a IdentSet,
153     ) -> IdentRefSet<'a> {
154         match *self {
155             Data::Struct(ref v) => v.uses_type_params(options, type_set),
156             Data::Enum(ref v) => v.uses_type_params(options, type_set),
157         }
158     }
159 }
160 
161 impl<V: UsesLifetimes, F: UsesLifetimes> UsesLifetimes for Data<V, F> {
uses_lifetimes<'a>( &self, options: &usage::Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>162     fn uses_lifetimes<'a>(
163         &self,
164         options: &usage::Options,
165         lifetimes: &'a LifetimeSet,
166     ) -> LifetimeRefSet<'a> {
167         match *self {
168             Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes),
169             Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes),
170         }
171     }
172 }
173 
174 /// Equivalent to `syn::Fields`, but replaces the AST element with a generic.
175 #[derive(Debug, Clone)]
176 pub struct Fields<T> {
177     pub style: Style,
178     pub fields: Vec<T>,
179     span: Option<Span>,
180     __nonexhaustive: (),
181 }
182 
183 impl<T> Fields<T> {
184     /// Creates a new [`Fields`] struct.
new(style: Style, fields: Vec<T>) -> Self185     pub fn new(style: Style, fields: Vec<T>) -> Self {
186         Self {
187             style,
188             fields,
189             span: None,
190             __nonexhaustive: (),
191         }
192     }
193 
194     /// Adds a [`Span`] to [`Fields`].
with_span(mut self, span: Span) -> Self195     pub fn with_span(mut self, span: Span) -> Self {
196         if self.span.is_none() {
197             self.span = Some(span);
198         }
199         self
200     }
201 
empty_from(vd: &syn::Fields) -> Self202     pub fn empty_from(vd: &syn::Fields) -> Self {
203         Self::new(vd.into(), Vec::new())
204     }
205 
206     /// Splits the `Fields` into its style and fields for further processing.
207     /// Returns an empty `Vec` for `Unit` data.
split(self) -> (Style, Vec<T>)208     pub fn split(self) -> (Style, Vec<T>) {
209         (self.style, self.fields)
210     }
211 
212     /// Returns true if this variant's data makes it a newtype.
is_newtype(&self) -> bool213     pub fn is_newtype(&self) -> bool {
214         self.style == Style::Tuple && self.len() == 1
215     }
216 
is_unit(&self) -> bool217     pub fn is_unit(&self) -> bool {
218         self.style.is_unit()
219     }
220 
is_tuple(&self) -> bool221     pub fn is_tuple(&self) -> bool {
222         self.style.is_tuple()
223     }
224 
is_struct(&self) -> bool225     pub fn is_struct(&self) -> bool {
226         self.style.is_struct()
227     }
228 
as_ref<'a>(&'a self) -> Fields<&'a T>229     pub fn as_ref<'a>(&'a self) -> Fields<&'a T> {
230         Fields {
231             style: self.style,
232             fields: self.fields.iter().collect(),
233             span: self.span,
234             __nonexhaustive: (),
235         }
236     }
237 
map<F, U>(self, map: F) -> Fields<U> where F: FnMut(T) -> U,238     pub fn map<F, U>(self, map: F) -> Fields<U>
239     where
240         F: FnMut(T) -> U,
241     {
242         Fields {
243             style: self.style,
244             fields: self.fields.into_iter().map(map).collect(),
245             span: self.span,
246             __nonexhaustive: (),
247         }
248     }
249 
iter(&self) -> slice::Iter<T>250     pub fn iter(&self) -> slice::Iter<T> {
251         self.fields.iter()
252     }
253 
254     /// Returns the number of fields in the structure.
len(&self) -> usize255     pub fn len(&self) -> usize {
256         self.fields.len()
257     }
258 
259     /// Returns `true` if the `Fields` contains no fields.
is_empty(&self) -> bool260     pub fn is_empty(&self) -> bool {
261         self.fields.is_empty()
262     }
263 }
264 
265 impl<F: FromField> Fields<F> {
try_from(fields: &syn::Fields) -> Result<Self>266     pub fn try_from(fields: &syn::Fields) -> Result<Self> {
267         let (items, errors) = {
268             match &fields {
269                 syn::Fields::Named(fields) => {
270                     let mut items = Vec::with_capacity(fields.named.len());
271                     let mut errors = Vec::new();
272 
273                     for field in &fields.named {
274                         match FromField::from_field(field) {
275                             Ok(val) => items.push(val),
276                             Err(err) => errors.push({
277                                 if let Some(ident) = &field.ident {
278                                     err.at(ident)
279                                 } else {
280                                     err
281                                 }
282                             }),
283                         }
284                     }
285 
286                     (items, errors)
287                 }
288                 syn::Fields::Unnamed(fields) => {
289                     let mut items = Vec::with_capacity(fields.unnamed.len());
290                     let mut errors = Vec::new();
291 
292                     for field in &fields.unnamed {
293                         match FromField::from_field(field) {
294                             Ok(val) => items.push(val),
295                             Err(err) => errors.push({
296                                 if let Some(ident) = &field.ident {
297                                     err.at(ident)
298                                 } else {
299                                     err
300                                 }
301                             }),
302                         }
303                     }
304 
305                     (items, errors)
306                 }
307                 syn::Fields::Unit => (vec![], vec![]),
308             }
309         };
310 
311         if !errors.is_empty() {
312             Err(Error::multiple(errors))
313         } else {
314             Ok(Self::new(fields.into(), items).with_span(fields.span()))
315         }
316     }
317 }
318 
319 impl<T: ToTokens> ToTokens for Fields<T> {
to_tokens(&self, tokens: &mut TokenStream)320     fn to_tokens(&self, tokens: &mut TokenStream) {
321         let fields = &self.fields;
322         // An unknown Span should be `Span::call_site()`;
323         // https://docs.rs/syn/1.0.12/syn/spanned/trait.Spanned.html#tymethod.span
324         let span = self.span.unwrap_or_else(Span::call_site);
325 
326         match self.style {
327             Style::Struct => {
328                 let trailing_comma = {
329                     if fields.is_empty() {
330                         quote!()
331                     } else {
332                         quote!(,)
333                     }
334                 };
335 
336                 tokens.extend(quote_spanned![span => { #(#fields),* #trailing_comma }]);
337             }
338             Style::Tuple => {
339                 tokens.extend(quote_spanned![span => ( #(#fields),* )]);
340             }
341             Style::Unit => {}
342         }
343     }
344 }
345 
346 impl<T: PartialEq> PartialEq for Fields<T> {
eq(&self, other: &Self) -> bool347     fn eq(&self, other: &Self) -> bool {
348         self.style == other.style && self.fields == other.fields
349     }
350 }
351 
352 impl<T: Eq> Eq for Fields<T> {}
353 
354 impl<T> IntoIterator for Fields<T> {
355     type Item = T;
356     type IntoIter = vec::IntoIter<T>;
357 
into_iter(self) -> Self::IntoIter358     fn into_iter(self) -> Self::IntoIter {
359         self.fields.into_iter()
360     }
361 }
362 
363 impl<T> From<Style> for Fields<T> {
from(style: Style) -> Self364     fn from(style: Style) -> Self {
365         Self::new(style, Vec::new())
366     }
367 }
368 
369 impl<T, U: Into<Vec<T>>> From<(Style, U)> for Fields<T> {
from((style, fields): (Style, U)) -> Self370     fn from((style, fields): (Style, U)) -> Self {
371         style.with_fields(fields)
372     }
373 }
374 
375 impl<T: UsesTypeParams> UsesTypeParams for Fields<T> {
uses_type_params<'a>( &self, options: &usage::Options, type_set: &'a IdentSet, ) -> IdentRefSet<'a>376     fn uses_type_params<'a>(
377         &self,
378         options: &usage::Options,
379         type_set: &'a IdentSet,
380     ) -> IdentRefSet<'a> {
381         self.fields.uses_type_params(options, type_set)
382     }
383 }
384 
385 impl<T: UsesLifetimes> UsesLifetimes for Fields<T> {
uses_lifetimes<'a>( &self, options: &usage::Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>386     fn uses_lifetimes<'a>(
387         &self,
388         options: &usage::Options,
389         lifetimes: &'a LifetimeSet,
390     ) -> LifetimeRefSet<'a> {
391         self.fields.uses_lifetimes(options, lifetimes)
392     }
393 }
394 
395 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
396 pub enum Style {
397     Tuple,
398     Struct,
399     Unit,
400 }
401 
402 impl Style {
is_unit(self) -> bool403     pub fn is_unit(self) -> bool {
404         self == Style::Unit
405     }
406 
is_tuple(self) -> bool407     pub fn is_tuple(self) -> bool {
408         self == Style::Tuple
409     }
410 
is_struct(self) -> bool411     pub fn is_struct(self) -> bool {
412         self == Style::Struct
413     }
414 
415     /// Creates a new `Fields` of the specified style with the passed-in fields.
with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> Fields<T>416     fn with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> Fields<T> {
417         Fields::new(self, fields.into())
418     }
419 }
420 
421 impl From<syn::Fields> for Style {
from(vd: syn::Fields) -> Self422     fn from(vd: syn::Fields) -> Self {
423         (&vd).into()
424     }
425 }
426 
427 impl<'a> From<&'a syn::Fields> for Style {
from(vd: &syn::Fields) -> Self428     fn from(vd: &syn::Fields) -> Self {
429         match *vd {
430             syn::Fields::Named(_) => Style::Struct,
431             syn::Fields::Unnamed(_) => Style::Tuple,
432             syn::Fields::Unit => Style::Unit,
433         }
434     }
435 }
436 
437 #[cfg(test)]
438 mod tests {
439     use super::*;
440 
441     // it is not possible to directly convert a TokenStream into syn::Fields, so you have
442     // to convert the TokenStream into DeriveInput first and then pass the syn::Fields to
443     // Fields::try_from.
token_stream_to_fields(input: TokenStream) -> Fields<syn::Field>444     fn token_stream_to_fields(input: TokenStream) -> Fields<syn::Field> {
445         Fields::try_from(&{
446             if let syn::Data::Struct(s) =
447                 syn::parse2::<syn::DeriveInput>(input.clone()).unwrap().data
448             {
449                 s.fields
450             } else {
451                 panic!();
452             }
453         })
454         .unwrap()
455     }
456 
457     #[test]
test_style_eq()458     fn test_style_eq() {
459         // `Fields` implements `Eq` manually, so it has to be ensured, that all fields of `Fields`
460         // implement `Eq`, this test would fail, if someone accidentally removed the Eq
461         // implementation from `Style`.
462         struct _AssertEq
463         where
464             Style: Eq;
465     }
466 
467     #[test]
test_fields_to_tokens_struct()468     fn test_fields_to_tokens_struct() {
469         let reference = quote!(
470             {
471                 executable: String,
472                 args: Vec<String>,
473                 env: Vec<String>,
474                 index: usize,
475                 optional: Option<String>,
476                 current_dir: String,
477             }
478         );
479         let input = quote!(
480             struct ExampleTest #reference
481         );
482 
483         let fields = token_stream_to_fields(input);
484 
485         let mut result = quote!();
486         fields.to_tokens(&mut result);
487         assert_eq!(result.to_string(), reference.to_string());
488     }
489 
490     #[test]
test_fields_to_tokens_tuple()491     fn test_fields_to_tokens_tuple() {
492         let reference = quote!((u64, usize, &'a T));
493         let input = quote!(
494             struct ExampleTest #reference;
495         );
496 
497         let fields = token_stream_to_fields(input);
498 
499         let mut result = quote!();
500         fields.to_tokens(&mut result);
501         assert_eq!(result.to_string(), reference.to_string());
502     }
503 }
504