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
12pub use nested_meta::NestedMeta;
13
14mod nested_meta;
15
16#[derive(Debug, Clone, PartialEq, Eq)]
20pub enum Data<V, F> {
21 Enum(Vec<V>),
22 Struct(Fields<F>),
23}
24
25impl<V, F> Data<V, F> {
26 pub fn empty_from(src: &syn::Data) -> Self {
31 match *src {
32 syn::Data::Enum(_) => Data::Enum(vec![]),
33 syn::Data::Struct(ref vd) => Data::Struct(Fields::empty_from(&vd.fields)),
34 syn::Data::Union(_) => panic!("Unions are not supported"),
35 }
36 }
37
38 pub fn try_empty_from(src: &syn::Data) -> Result<Self> {
42 match *src {
43 syn::Data::Enum(_) => Ok(Data::Enum(vec![])),
44 syn::Data::Struct(ref vd) => Ok(Data::Struct(Fields::empty_from(&vd.fields))),
45 syn::Data::Union(_) => Err(Error::custom("Unions are not supported")),
49 }
50 }
51
52 pub fn as_ref(&self) -> Data<&V, &F> {
54 match *self {
55 Data::Enum(ref variants) => Data::Enum(variants.iter().collect()),
56 Data::Struct(ref data) => Data::Struct(data.as_ref()),
57 }
58 }
59
60 pub fn map_enum_variants<T, U>(self, map: T) -> Data<U, F>
62 where
63 T: FnMut(V) -> U,
64 {
65 match self {
66 Data::Enum(v) => Data::Enum(v.into_iter().map(map).collect()),
67 Data::Struct(f) => Data::Struct(f),
68 }
69 }
70
71 pub fn map_struct_fields<T, U>(self, map: T) -> Data<V, U>
73 where
74 T: FnMut(F) -> U,
75 {
76 match self {
77 Data::Enum(v) => Data::Enum(v),
78 Data::Struct(f) => Data::Struct(f.map(map)),
79 }
80 }
81
82 pub fn map_struct<T, U>(self, mut map: T) -> Data<V, U>
84 where
85 T: FnMut(Fields<F>) -> Fields<U>,
86 {
87 match self {
88 Data::Enum(v) => Data::Enum(v),
89 Data::Struct(f) => Data::Struct(map(f)),
90 }
91 }
92
93 pub fn take_struct(self) -> Option<Fields<F>> {
95 match self {
96 Data::Enum(_) => None,
97 Data::Struct(f) => Some(f),
98 }
99 }
100
101 pub fn take_enum(self) -> Option<Vec<V>> {
103 match self {
104 Data::Enum(v) => Some(v),
105 Data::Struct(_) => None,
106 }
107 }
108
109 pub fn is_enum(&self) -> bool {
111 match *self {
112 Data::Enum(_) => true,
113 Data::Struct(_) => false,
114 }
115 }
116
117 pub fn is_struct(&self) -> bool {
119 !self.is_enum()
120 }
121}
122
123impl<V: FromVariant, F: FromField> Data<V, F> {
124 pub fn try_from(body: &syn::Data) -> Result<Self> {
126 match *body {
127 syn::Data::Enum(ref data) => {
128 let mut errors = Error::accumulator();
129 let items = data
130 .variants
131 .iter()
132 .filter_map(|v| errors.handle(FromVariant::from_variant(v)))
133 .collect();
134
135 errors.finish_with(Data::Enum(items))
136 }
137 syn::Data::Struct(ref data) => Ok(Data::Struct(Fields::try_from(&data.fields)?)),
138 syn::Data::Union(_) => Err(Error::custom("Unions are not supported")),
142 }
143 }
144}
145
146impl<V: UsesTypeParams, F: UsesTypeParams> UsesTypeParams for Data<V, F> {
147 fn uses_type_params<'a>(
148 &self,
149 options: &usage::Options,
150 type_set: &'a IdentSet,
151 ) -> IdentRefSet<'a> {
152 match *self {
153 Data::Struct(ref v) => v.uses_type_params(options, type_set),
154 Data::Enum(ref v) => v.uses_type_params(options, type_set),
155 }
156 }
157}
158
159impl<V: UsesLifetimes, F: UsesLifetimes> UsesLifetimes for Data<V, F> {
160 fn uses_lifetimes<'a>(
161 &self,
162 options: &usage::Options,
163 lifetimes: &'a LifetimeSet,
164 ) -> LifetimeRefSet<'a> {
165 match *self {
166 Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes),
167 Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes),
168 }
169 }
170}
171
172#[derive(Debug, Clone)]
174pub struct Fields<T> {
175 pub style: Style,
176 pub fields: Vec<T>,
177 span: Option<Span>,
178 __nonexhaustive: (),
179}
180
181impl<T> Fields<T> {
182 pub fn new(style: Style, fields: Vec<T>) -> Self {
184 Self {
185 style,
186 fields,
187 span: None,
188 __nonexhaustive: (),
189 }
190 }
191
192 pub fn with_span(mut self, span: Span) -> Self {
194 if self.span.is_none() {
195 self.span = Some(span);
196 }
197 self
198 }
199
200 pub fn empty_from(vd: &syn::Fields) -> Self {
201 Self::new(vd.into(), Vec::new())
202 }
203
204 pub fn split(self) -> (Style, Vec<T>) {
207 (self.style, self.fields)
208 }
209
210 pub fn is_newtype(&self) -> bool {
212 self.style == Style::Tuple && self.len() == 1
213 }
214
215 pub fn is_unit(&self) -> bool {
216 self.style.is_unit()
217 }
218
219 pub fn is_tuple(&self) -> bool {
220 self.style.is_tuple()
221 }
222
223 pub fn is_struct(&self) -> bool {
224 self.style.is_struct()
225 }
226
227 pub fn as_ref(&self) -> Fields<&T> {
228 Fields {
229 style: self.style,
230 fields: self.fields.iter().collect(),
231 span: self.span,
232 __nonexhaustive: (),
233 }
234 }
235
236 pub fn map<F, U>(self, map: F) -> Fields<U>
237 where
238 F: FnMut(T) -> U,
239 {
240 Fields {
241 style: self.style,
242 fields: self.fields.into_iter().map(map).collect(),
243 span: self.span,
244 __nonexhaustive: (),
245 }
246 }
247
248 pub fn iter(&self) -> slice::Iter<'_, T> {
249 self.fields.iter()
250 }
251
252 pub fn len(&self) -> usize {
254 self.fields.len()
255 }
256
257 pub fn is_empty(&self) -> bool {
259 self.fields.is_empty()
260 }
261}
262
263impl<F: FromField> Fields<F> {
264 pub fn try_from(fields: &syn::Fields) -> Result<Self> {
265 let mut errors = Error::accumulator();
266 let items = {
267 match &fields {
268 syn::Fields::Named(fields) => fields
269 .named
270 .iter()
271 .filter_map(|field| {
272 errors.handle(FromField::from_field(field).map_err(|err| {
273 if let Some(ident) = &field.ident {
277 err.at(ident)
278 } else {
279 err
280 }
281 }))
282 })
283 .collect(),
284 syn::Fields::Unnamed(fields) => fields
285 .unnamed
286 .iter()
287 .filter_map(|field| errors.handle(FromField::from_field(field)))
288 .collect(),
289 syn::Fields::Unit => vec![],
290 }
291 };
292
293 errors.finish()?;
294
295 Ok(Self::new(fields.into(), items).with_span(fields.span()))
296 }
297}
298
299impl<T: ToTokens> ToTokens for Fields<T> {
300 fn to_tokens(&self, tokens: &mut TokenStream) {
301 let fields = &self.fields;
302 let span = self.span.unwrap_or_else(Span::call_site);
305
306 match self.style {
307 Style::Struct => {
308 let trailing_comma = {
309 if fields.is_empty() {
310 quote!()
311 } else {
312 quote!(,)
313 }
314 };
315
316 tokens.extend(quote_spanned![span => { #(#fields),* #trailing_comma }]);
317 }
318 Style::Tuple => {
319 tokens.extend(quote_spanned![span => ( #(#fields),* )]);
320 }
321 Style::Unit => {}
322 }
323 }
324}
325
326impl<T: PartialEq> PartialEq for Fields<T> {
327 fn eq(&self, other: &Self) -> bool {
328 self.style == other.style && self.fields == other.fields
329 }
330}
331
332impl<T: Eq> Eq for Fields<T> {}
333
334impl<T> IntoIterator for Fields<T> {
335 type Item = T;
336 type IntoIter = vec::IntoIter<T>;
337
338 fn into_iter(self) -> Self::IntoIter {
339 self.fields.into_iter()
340 }
341}
342
343impl<T> From<Style> for Fields<T> {
344 fn from(style: Style) -> Self {
345 Self::new(style, Vec::new())
346 }
347}
348
349impl<T, U: Into<Vec<T>>> From<(Style, U)> for Fields<T> {
350 fn from((style, fields): (Style, U)) -> Self {
351 style.with_fields(fields)
352 }
353}
354
355impl<T: UsesTypeParams> UsesTypeParams for Fields<T> {
356 fn uses_type_params<'a>(
357 &self,
358 options: &usage::Options,
359 type_set: &'a IdentSet,
360 ) -> IdentRefSet<'a> {
361 self.fields.uses_type_params(options, type_set)
362 }
363}
364
365impl<T: UsesLifetimes> UsesLifetimes for Fields<T> {
366 fn uses_lifetimes<'a>(
367 &self,
368 options: &usage::Options,
369 lifetimes: &'a LifetimeSet,
370 ) -> LifetimeRefSet<'a> {
371 self.fields.uses_lifetimes(options, lifetimes)
372 }
373}
374
375#[derive(Debug, Clone, Copy, PartialEq, Eq)]
376pub enum Style {
377 Tuple,
378 Struct,
379 Unit,
380}
381
382impl Style {
383 pub fn is_unit(self) -> bool {
384 self == Style::Unit
385 }
386
387 pub fn is_tuple(self) -> bool {
388 self == Style::Tuple
389 }
390
391 pub fn is_struct(self) -> bool {
392 self == Style::Struct
393 }
394
395 fn with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> Fields<T> {
397 Fields::new(self, fields.into())
398 }
399}
400
401impl From<syn::Fields> for Style {
402 fn from(vd: syn::Fields) -> Self {
403 (&vd).into()
404 }
405}
406
407impl From<&syn::Fields> for Style {
408 fn from(vd: &syn::Fields) -> Self {
409 match *vd {
410 syn::Fields::Named(_) => Style::Struct,
411 syn::Fields::Unnamed(_) => Style::Tuple,
412 syn::Fields::Unit => Style::Unit,
413 }
414 }
415}
416
417#[cfg(test)]
418mod tests {
419 use super::*;
420
421 fn token_stream_to_fields(input: TokenStream) -> Fields<syn::Field> {
425 Fields::try_from(&{
426 if let syn::Data::Struct(s) = syn::parse2::<syn::DeriveInput>(input).unwrap().data {
427 s.fields
428 } else {
429 panic!();
430 }
431 })
432 .unwrap()
433 }
434
435 #[test]
436 fn test_style_eq() {
437 struct _AssertEq
441 where
442 Style: Eq;
443 }
444
445 #[test]
446 fn test_fields_to_tokens_struct() {
447 let reference = quote!(
448 {
449 executable: String,
450 args: Vec<String>,
451 env: Vec<String>,
452 index: usize,
453 optional: Option<String>,
454 current_dir: String,
455 }
456 );
457 let input = quote!(
458 struct ExampleTest #reference
459 );
460
461 let fields = token_stream_to_fields(input);
462
463 let mut result = quote!();
464 fields.to_tokens(&mut result);
465 assert_eq!(result.to_string(), reference.to_string());
466 }
467
468 #[test]
469 fn test_fields_to_tokens_tuple() {
470 let reference = quote!((u64, usize, &'a T));
471 let input = quote!(
472 struct ExampleTest #reference;
473 );
474
475 let fields = token_stream_to_fields(input);
476
477 let mut result = quote!();
478 fields.to_tokens(&mut result);
479 assert_eq!(result.to_string(), reference.to_string());
480 }
481}