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