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::{MetaNameValueInvalidExpr, 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 as_struct(&self) -> Option<&Fields<F>> {
111 match self {
112 Data::Enum(_) => None,
113 Data::Struct(f) => Some(f),
114 }
115 }
116
117 pub fn as_enum(&self) -> Option<&[V]> {
119 match self {
120 Data::Enum(v) => Some(v),
121 Data::Struct(_) => None,
122 }
123 }
124
125 pub fn is_enum(&self) -> bool {
127 match *self {
128 Data::Enum(_) => true,
129 Data::Struct(_) => false,
130 }
131 }
132
133 pub fn is_struct(&self) -> bool {
135 !self.is_enum()
136 }
137}
138
139impl<V: FromVariant, F: FromField> Data<V, F> {
140 pub fn try_from(body: &syn::Data) -> Result<Self> {
142 match *body {
143 syn::Data::Enum(ref data) => {
144 let mut errors = Error::accumulator();
145 let items = data
146 .variants
147 .iter()
148 .filter_map(|v| errors.handle(FromVariant::from_variant(v)))
149 .collect();
150
151 errors.finish_with(Data::Enum(items))
152 }
153 syn::Data::Struct(ref data) => Ok(Data::Struct(Fields::try_from(&data.fields)?)),
154 syn::Data::Union(_) => Err(Error::custom("Unions are not supported")),
158 }
159 }
160}
161
162impl<'a, V: FromVariant, F: FromField> TryFrom<&'a syn::Data> for Data<V, F> {
163 type Error = Error;
164
165 fn try_from(value: &'a syn::Data) -> Result<Self> {
166 Data::try_from(value)
167 }
168}
169
170impl<V: UsesTypeParams, F: UsesTypeParams> UsesTypeParams for Data<V, F> {
171 fn uses_type_params<'a>(
172 &self,
173 options: &usage::Options,
174 type_set: &'a IdentSet,
175 ) -> IdentRefSet<'a> {
176 match *self {
177 Data::Struct(ref v) => v.uses_type_params(options, type_set),
178 Data::Enum(ref v) => v.uses_type_params(options, type_set),
179 }
180 }
181}
182
183impl<V: UsesLifetimes, F: UsesLifetimes> UsesLifetimes for Data<V, F> {
184 fn uses_lifetimes<'a>(
185 &self,
186 options: &usage::Options,
187 lifetimes: &'a LifetimeSet,
188 ) -> LifetimeRefSet<'a> {
189 match *self {
190 Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes),
191 Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes),
192 }
193 }
194}
195
196#[derive(Debug, Clone)]
198pub struct Fields<T> {
199 pub style: Style,
200 pub fields: Vec<T>,
201 span: Option<Span>,
202 __nonexhaustive: (),
203}
204
205impl<T> Fields<T> {
206 pub fn new(style: Style, fields: Vec<T>) -> Self {
208 Self {
209 style,
210 fields,
211 span: None,
212 __nonexhaustive: (),
213 }
214 }
215
216 pub fn with_span(mut self, span: Span) -> Self {
218 if self.span.is_none() {
219 self.span = Some(span);
220 }
221 self
222 }
223
224 pub fn empty_from(vd: &syn::Fields) -> Self {
225 Self::new(vd.into(), Vec::new())
226 }
227
228 pub fn split(self) -> (Style, Vec<T>) {
231 (self.style, self.fields)
232 }
233
234 pub fn is_unit(&self) -> bool {
235 self.style.is_unit()
236 }
237
238 pub fn is_tuple(&self) -> bool {
239 self.style.is_tuple()
240 }
241
242 pub fn is_struct(&self) -> bool {
243 self.style.is_struct()
244 }
245
246 pub fn as_ref(&self) -> Fields<&T> {
247 Fields {
248 style: self.style,
249 fields: self.fields.iter().collect(),
250 span: self.span,
251 __nonexhaustive: (),
252 }
253 }
254
255 pub fn map<F, U>(self, map: F) -> Fields<U>
256 where
257 F: FnMut(T) -> U,
258 {
259 Fields {
260 style: self.style,
261 fields: self.fields.into_iter().map(map).collect(),
262 span: self.span,
263 __nonexhaustive: (),
264 }
265 }
266
267 pub fn iter(&self) -> slice::Iter<'_, T> {
268 self.fields.iter()
269 }
270
271 pub fn len(&self) -> usize {
273 self.fields.len()
274 }
275
276 pub fn is_empty(&self) -> bool {
278 self.fields.is_empty()
279 }
280}
281
282impl<F: FromField> Fields<F> {
283 pub fn try_from(fields: &syn::Fields) -> Result<Self> {
284 let mut errors = Error::accumulator();
285 let items = {
286 match &fields {
287 syn::Fields::Named(fields) => fields
288 .named
289 .iter()
290 .filter_map(|field| {
291 errors.handle(FromField::from_field(field).map_err(|err| {
292 if let Some(ident) = &field.ident {
296 err.at(ident)
297 } else {
298 err
299 }
300 }))
301 })
302 .collect(),
303 syn::Fields::Unnamed(fields) => fields
304 .unnamed
305 .iter()
306 .filter_map(|field| errors.handle(FromField::from_field(field)))
307 .collect(),
308 syn::Fields::Unit => vec![],
309 }
310 };
311
312 errors.finish()?;
313
314 Ok(Self::new(fields.into(), items).with_span(fields.span()))
315 }
316}
317
318impl<T: ToTokens> ToTokens for Fields<T> {
319 fn to_tokens(&self, tokens: &mut TokenStream) {
320 let fields = &self.fields;
321 let span = self.span.unwrap_or_else(Span::call_site);
324
325 match self.style {
326 Style::Struct => {
327 let trailing_comma = {
328 if fields.is_empty() {
329 quote!()
330 } else {
331 quote!(,)
332 }
333 };
334
335 tokens.extend(quote_spanned![span => { #(#fields),* #trailing_comma }]);
336 }
337 Style::Tuple => {
338 tokens.extend(quote_spanned![span => ( #(#fields),* )]);
339 }
340 Style::Unit => {}
341 }
342 }
343}
344
345impl<T: PartialEq> PartialEq for Fields<T> {
346 fn eq(&self, other: &Self) -> bool {
347 self.style == other.style && self.fields == other.fields
348 }
349}
350
351impl<T: Eq> Eq for Fields<T> {}
352
353impl<T> IntoIterator for Fields<T> {
354 type Item = T;
355 type IntoIter = vec::IntoIter<T>;
356
357 fn into_iter(self) -> Self::IntoIter {
358 self.fields.into_iter()
359 }
360}
361
362impl<T> From<Style> for Fields<T> {
363 fn from(style: Style) -> Self {
364 Self::new(style, Vec::new())
365 }
366}
367
368impl<T, U: Into<Vec<T>>> From<(Style, U)> for Fields<T> {
369 fn from((style, fields): (Style, U)) -> Self {
370 style.with_fields(fields)
371 }
372}
373
374impl<T: UsesTypeParams> UsesTypeParams for Fields<T> {
375 fn uses_type_params<'a>(
376 &self,
377 options: &usage::Options,
378 type_set: &'a IdentSet,
379 ) -> IdentRefSet<'a> {
380 self.fields.uses_type_params(options, type_set)
381 }
382}
383
384impl<T: UsesLifetimes> UsesLifetimes for Fields<T> {
385 fn uses_lifetimes<'a>(
386 &self,
387 options: &usage::Options,
388 lifetimes: &'a LifetimeSet,
389 ) -> LifetimeRefSet<'a> {
390 self.fields.uses_lifetimes(options, lifetimes)
391 }
392}
393
394#[derive(Debug, Clone, Copy, PartialEq, Eq)]
395pub enum Style {
396 Tuple,
397 Struct,
398 Unit,
399}
400
401impl Style {
402 pub fn is_unit(self) -> bool {
403 self == Style::Unit
404 }
405
406 pub fn is_tuple(self) -> bool {
407 self == Style::Tuple
408 }
409
410 pub fn is_struct(self) -> bool {
411 self == Style::Struct
412 }
413
414 fn with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> Fields<T> {
416 Fields::new(self, fields.into())
417 }
418}
419
420impl From<syn::Fields> for Style {
421 fn from(vd: syn::Fields) -> Self {
422 (&vd).into()
423 }
424}
425
426impl From<&syn::Fields> for Style {
427 fn from(vd: &syn::Fields) -> Self {
428 match *vd {
429 syn::Fields::Named(_) => Style::Struct,
430 syn::Fields::Unnamed(_) => Style::Tuple,
431 syn::Fields::Unit => Style::Unit,
432 }
433 }
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439
440 fn token_stream_to_fields(input: TokenStream) -> Fields<syn::Field> {
444 Fields::try_from(&{
445 if let syn::Data::Struct(s) = syn::parse2::<syn::DeriveInput>(input).unwrap().data {
446 s.fields
447 } else {
448 panic!();
449 }
450 })
451 .unwrap()
452 }
453
454 #[test]
455 fn test_style_eq() {
456 struct _AssertEq
460 where
461 Style: Eq;
462 }
463
464 #[test]
465 fn test_fields_to_tokens_struct() {
466 let reference = quote!(
467 {
468 executable: String,
469 args: Vec<String>,
470 env: Vec<String>,
471 index: usize,
472 optional: Option<String>,
473 current_dir: String,
474 }
475 );
476 let input = quote!(
477 struct ExampleTest #reference
478 );
479
480 let fields = token_stream_to_fields(input);
481
482 let mut result = quote!();
483 fields.to_tokens(&mut result);
484 assert_eq!(result.to_string(), reference.to_string());
485 }
486
487 #[test]
488 fn test_fields_to_tokens_tuple() {
489 let reference = quote!((u64, usize, &'a T));
490 let input = quote!(
491 struct ExampleTest #reference;
492 );
493
494 let fields = token_stream_to_fields(input);
495
496 let mut result = quote!();
497 fields.to_tokens(&mut result);
498 assert_eq!(result.to_string(), reference.to_string());
499 }
500}