1use std::{slice, vec};
2
3use proc_macro2::{Span, TokenStream};
4use quote::{quote, quote_spanned, ToTokens};
5use syn::spanned::Spanned;
6
7use crate::usage::{
8 self, IdentRefSet, IdentSet, LifetimeRefSet, LifetimeSet, UsesLifetimes, UsesTypeParams,
9};
10use crate::{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)]
16pub enum Data<V, F> {
17 Enum(Vec<V>),
18 Struct(Fields<F>),
19}
20
21impl<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`.
26 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.
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>`.
49 pub fn as_ref(&self) -> Data<&V, &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.
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.
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.
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.
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.
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`.
106 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`.
114 pub fn is_struct(&self) -> bool {
115 !self.is_enum()
116 }
117}
118
119impl<V: FromVariant, F: FromField> Data<V, F> {
120 /// Attempt to convert from a `syn::Data` instance.
121 pub fn try_from(body: &syn::Data) -> Result<Self> {
122 match *body {
123 syn::Data::Enum(ref data: &DataEnum) => {
124 let mut errors: Accumulator = Error::accumulator();
125 let items: Vec = dataimpl Iterator
126 .variants
127 .iter()
128 .filter_map(|v: &Variant| errors.handle(result:FromVariant::from_variant(v)))
129 .collect();
130
131 errors.finish_with(success:Data::Enum(items))
132 }
133 syn::Data::Struct(ref data: &DataStruct) => Ok(Data::Struct(Fields::try_from(&data.fields)?)),
134 // This deliberately doesn't set a span on the error message, as the error is most useful if
135 // applied to the call site of the offending macro. Given that the message is very generic,
136 // putting it on the union keyword ends up being confusing.
137 syn::Data::Union(_) => Err(Error::custom(msg:"Unions are not supported")),
138 }
139 }
140}
141
142impl<V: UsesTypeParams, F: UsesTypeParams> UsesTypeParams for Data<V, F> {
143 fn uses_type_params<'a>(
144 &self,
145 options: &usage::Options,
146 type_set: &'a IdentSet,
147 ) -> IdentRefSet<'a> {
148 match *self {
149 Data::Struct(ref v: &Fields) => v.uses_type_params(options, type_set),
150 Data::Enum(ref v: &Vec) => v.uses_type_params(options, type_set),
151 }
152 }
153}
154
155impl<V: UsesLifetimes, F: UsesLifetimes> UsesLifetimes for Data<V, F> {
156 fn uses_lifetimes<'a>(
157 &self,
158 options: &usage::Options,
159 lifetimes: &'a LifetimeSet,
160 ) -> LifetimeRefSet<'a> {
161 match *self {
162 Data::Struct(ref v: &Fields) => v.uses_lifetimes(options, lifetimes),
163 Data::Enum(ref v: &Vec) => v.uses_lifetimes(options, lifetimes),
164 }
165 }
166}
167
168/// Equivalent to `syn::Fields`, but replaces the AST element with a generic.
169#[derive(Debug, Clone)]
170pub struct Fields<T> {
171 pub style: Style,
172 pub fields: Vec<T>,
173 span: Option<Span>,
174 __nonexhaustive: (),
175}
176
177impl<T> Fields<T> {
178 /// Creates a new [`Fields`] struct.
179 pub fn new(style: Style, fields: Vec<T>) -> Self {
180 Self {
181 style,
182 fields,
183 span: None,
184 __nonexhaustive: (),
185 }
186 }
187
188 /// Adds a [`Span`] to [`Fields`].
189 pub fn with_span(mut self, span: Span) -> Self {
190 if self.span.is_none() {
191 self.span = Some(span);
192 }
193 self
194 }
195
196 pub fn empty_from(vd: &syn::Fields) -> Self {
197 Self::new(vd.into(), Vec::new())
198 }
199
200 /// Splits the `Fields` into its style and fields for further processing.
201 /// Returns an empty `Vec` for `Unit` data.
202 pub fn split(self) -> (Style, Vec<T>) {
203 (self.style, self.fields)
204 }
205
206 /// Returns true if this variant's data makes it a newtype.
207 pub fn is_newtype(&self) -> bool {
208 self.style == Style::Tuple && self.len() == 1
209 }
210
211 pub fn is_unit(&self) -> bool {
212 self.style.is_unit()
213 }
214
215 pub fn is_tuple(&self) -> bool {
216 self.style.is_tuple()
217 }
218
219 pub fn is_struct(&self) -> bool {
220 self.style.is_struct()
221 }
222
223 pub fn as_ref(&self) -> Fields<&T> {
224 Fields {
225 style: self.style,
226 fields: self.fields.iter().collect(),
227 span: self.span,
228 __nonexhaustive: (),
229 }
230 }
231
232 pub fn map<F, U>(self, map: F) -> Fields<U>
233 where
234 F: FnMut(T) -> U,
235 {
236 Fields {
237 style: self.style,
238 fields: self.fields.into_iter().map(map).collect(),
239 span: self.span,
240 __nonexhaustive: (),
241 }
242 }
243
244 pub fn iter(&self) -> slice::Iter<T> {
245 self.fields.iter()
246 }
247
248 /// Returns the number of fields in the structure.
249 pub fn len(&self) -> usize {
250 self.fields.len()
251 }
252
253 /// Returns `true` if the `Fields` contains no fields.
254 pub fn is_empty(&self) -> bool {
255 self.fields.is_empty()
256 }
257}
258
259impl<F: FromField> Fields<F> {
260 pub fn try_from(fields: &syn::Fields) -> Result<Self> {
261 let mut errors = Error::accumulator();
262 let items = {
263 match &fields {
264 syn::Fields::Named(fields) => fields
265 .named
266 .iter()
267 .filter_map(|field| {
268 errors.handle(FromField::from_field(field).map_err(|err| {
269 // There should always be an ident here, since this is a collection
270 // of named fields, but `syn` doesn't prevent someone from manually
271 // constructing an invalid collection so a guard is still warranted.
272 if let Some(ident) = &field.ident {
273 err.at(ident)
274 } else {
275 err
276 }
277 }))
278 })
279 .collect(),
280 syn::Fields::Unnamed(fields) => fields
281 .unnamed
282 .iter()
283 .filter_map(|field| errors.handle(FromField::from_field(field)))
284 .collect(),
285 syn::Fields::Unit => vec![],
286 }
287 };
288
289 errors.finish()?;
290
291 Ok(Self::new(fields.into(), items).with_span(fields.span()))
292 }
293}
294
295impl<T: ToTokens> ToTokens for Fields<T> {
296 fn to_tokens(&self, tokens: &mut TokenStream) {
297 let fields = &self.fields;
298 // An unknown Span should be `Span::call_site()`;
299 // https://docs.rs/syn/1.0.12/syn/spanned/trait.Spanned.html#tymethod.span
300 let span = self.span.unwrap_or_else(Span::call_site);
301
302 match self.style {
303 Style::Struct => {
304 let trailing_comma = {
305 if fields.is_empty() {
306 quote!()
307 } else {
308 quote!(,)
309 }
310 };
311
312 tokens.extend(quote_spanned![span => { #(#fields),* #trailing_comma }]);
313 }
314 Style::Tuple => {
315 tokens.extend(quote_spanned![span => ( #(#fields),* )]);
316 }
317 Style::Unit => {}
318 }
319 }
320}
321
322impl<T: PartialEq> PartialEq for Fields<T> {
323 fn eq(&self, other: &Self) -> bool {
324 self.style == other.style && self.fields == other.fields
325 }
326}
327
328impl<T: Eq> Eq for Fields<T> {}
329
330impl<T> IntoIterator for Fields<T> {
331 type Item = T;
332 type IntoIter = vec::IntoIter<T>;
333
334 fn into_iter(self) -> Self::IntoIter {
335 self.fields.into_iter()
336 }
337}
338
339impl<T> From<Style> for Fields<T> {
340 fn from(style: Style) -> Self {
341 Self::new(style, fields:Vec::new())
342 }
343}
344
345impl<T, U: Into<Vec<T>>> From<(Style, U)> for Fields<T> {
346 fn from((style: Style, fields: U): (Style, U)) -> Self {
347 style.with_fields(fields)
348 }
349}
350
351impl<T: UsesTypeParams> UsesTypeParams for Fields<T> {
352 fn uses_type_params<'a>(
353 &self,
354 options: &usage::Options,
355 type_set: &'a IdentSet,
356 ) -> IdentRefSet<'a> {
357 self.fields.uses_type_params(options, type_set)
358 }
359}
360
361impl<T: UsesLifetimes> UsesLifetimes for Fields<T> {
362 fn uses_lifetimes<'a>(
363 &self,
364 options: &usage::Options,
365 lifetimes: &'a LifetimeSet,
366 ) -> LifetimeRefSet<'a> {
367 self.fields.uses_lifetimes(options, lifetimes)
368 }
369}
370
371#[derive(Debug, Clone, Copy, PartialEq, Eq)]
372pub enum Style {
373 Tuple,
374 Struct,
375 Unit,
376}
377
378impl Style {
379 pub fn is_unit(self) -> bool {
380 self == Style::Unit
381 }
382
383 pub fn is_tuple(self) -> bool {
384 self == Style::Tuple
385 }
386
387 pub fn is_struct(self) -> bool {
388 self == Style::Struct
389 }
390
391 /// Creates a new `Fields` of the specified style with the passed-in fields.
392 fn with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> Fields<T> {
393 Fields::new(self, fields:fields.into())
394 }
395}
396
397impl From<syn::Fields> for Style {
398 fn from(vd: syn::Fields) -> Self {
399 (&vd).into()
400 }
401}
402
403impl<'a> From<&'a syn::Fields> for Style {
404 fn from(vd: &syn::Fields) -> Self {
405 match *vd {
406 syn::Fields::Named(_) => Style::Struct,
407 syn::Fields::Unnamed(_) => Style::Tuple,
408 syn::Fields::Unit => Style::Unit,
409 }
410 }
411}
412
413#[cfg(test)]
414mod tests {
415 use super::*;
416
417 // it is not possible to directly convert a TokenStream into syn::Fields, so you have
418 // to convert the TokenStream into DeriveInput first and then pass the syn::Fields to
419 // Fields::try_from.
420 fn token_stream_to_fields(input: TokenStream) -> Fields<syn::Field> {
421 Fields::try_from(&{
422 if let syn::Data::Struct(s) = syn::parse2::<syn::DeriveInput>(input).unwrap().data {
423 s.fields
424 } else {
425 panic!();
426 }
427 })
428 .unwrap()
429 }
430
431 #[test]
432 fn test_style_eq() {
433 // `Fields` implements `Eq` manually, so it has to be ensured, that all fields of `Fields`
434 // implement `Eq`, this test would fail, if someone accidentally removed the Eq
435 // implementation from `Style`.
436 struct _AssertEq
437 where
438 Style: Eq;
439 }
440
441 #[test]
442 fn test_fields_to_tokens_struct() {
443 let reference = quote!(
444 {
445 executable: String,
446 args: Vec<String>,
447 env: Vec<String>,
448 index: usize,
449 optional: Option<String>,
450 current_dir: String,
451 }
452 );
453 let input = quote!(
454 struct ExampleTest #reference
455 );
456
457 let fields = token_stream_to_fields(input);
458
459 let mut result = quote!();
460 fields.to_tokens(&mut result);
461 assert_eq!(result.to_string(), reference.to_string());
462 }
463
464 #[test]
465 fn test_fields_to_tokens_tuple() {
466 let reference = quote!((u64, usize, &'a T));
467 let input = quote!(
468 struct ExampleTest #reference;
469 );
470
471 let fields = token_stream_to_fields(input);
472
473 let mut result = quote!();
474 fields.to_tokens(&mut result);
475 assert_eq!(result.to_string(), reference.to_string());
476 }
477}
478