1//! Field parsing.
2
3use std::fmt::{self, Display, Formatter};
4
5use proc_macro2::{Span, TokenStream};
6use quote::{format_ident, IdentFragment, ToTokens};
7use syn::{ext::IdentExt, Attribute, FieldsNamed, FieldsUnnamed, Ident, Index, Result, Type};
8
9use crate::{DeriveWhere, FieldAttr, Skip, Trait};
10
11/// Struct, union, struct variant or tuple variant field.
12#[cfg_attr(test, derive(Debug))]
13pub struct Field<'a> {
14 /// Attributes.
15 pub attr: FieldAttr,
16 /// [`struct@Ident`] or [`Index`] for this field.
17 pub member: Member<'a>,
18 /// [`struct@Ident`] used as a Temporary variable for destructuring `self`.
19 pub self_ident: Ident,
20 /// [`struct@Ident`] used as a Temporary variable for destructuring `other`.
21 pub other_ident: Ident,
22 /// [`Type`] used for asserting traits on fields for [`Eq`].
23 pub type_: &'a Type,
24}
25
26/// Borrowed version of [`syn::Member`], to avoid unnecessary allocations.
27#[cfg_attr(test, derive(Debug))]
28pub enum Member<'a> {
29 /// Named field.
30 Named(&'a Ident),
31 /// Unnamed field.
32 Unnamed(Index),
33}
34
35impl IdentFragment for Member<'_> {
36 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
37 Display::fmt(&self, f)
38 }
39}
40
41impl ToTokens for Member<'_> {
42 fn to_tokens(&self, tokens: &mut TokenStream) {
43 match self {
44 Member::Named(ident: &&Ident) => ident.to_tokens(tokens),
45 Member::Unnamed(index: &Index) => index.to_tokens(tokens),
46 }
47 }
48}
49
50impl Display for Member<'_> {
51 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
52 match self {
53 Member::Named(ident: &&Ident) => write!(f, "{}", ident.unraw()),
54 Member::Unnamed(index: &Index) => write!(f, "{}", index.index),
55 }
56 }
57}
58
59impl<'a> Field<'a> {
60 /// Create [`Field`]s from [`syn::FieldsNamed`].
61 pub fn from_named(
62 derive_wheres: &[DeriveWhere],
63 skip_inner: &Skip,
64 fields: &'a FieldsNamed,
65 ) -> Result<Vec<Self>> {
66 fields
67 .named
68 .iter()
69 .map(|field| {
70 Field::from_field(
71 derive_wheres,
72 skip_inner,
73 &field.attrs,
74 Member::Named(field.ident.as_ref().expect("unexpected unnamed field")),
75 &field.ty,
76 )
77 })
78 .collect()
79 }
80
81 /// Create [`Field`]s from [`syn::FieldsUnnamed`].
82 pub fn from_unnamed(
83 derive_wheres: &[DeriveWhere],
84 skip_inner: &Skip,
85 fields: &'a FieldsUnnamed,
86 ) -> Result<Vec<Self>> {
87 (0_u32..)
88 .zip(&fields.unnamed)
89 .map(|(index, field)| {
90 Field::from_field(
91 derive_wheres,
92 skip_inner,
93 &field.attrs,
94 Member::Unnamed(Index {
95 index,
96 span: Span::call_site(),
97 }),
98 &field.ty,
99 )
100 })
101 .collect()
102 }
103
104 /// Create [`Field`] from [`syn::Field`].
105 fn from_field(
106 derive_wheres: &[DeriveWhere],
107 skip_inner: &Skip,
108 attrs: &[Attribute],
109 member: Member<'a>,
110 type_: &'a Type,
111 ) -> Result<Self> {
112 let attr = FieldAttr::from_attrs(derive_wheres, skip_inner, attrs)?;
113 let self_ident = format_ident!("__field_{}", member);
114 let other_ident = format_ident!("__other_field_{}", member);
115
116 Ok(Self {
117 attr,
118 member,
119 self_ident,
120 other_ident,
121 type_,
122 })
123 }
124
125 /// Convert to [`syn::Member`].
126 pub fn to_member(&self) -> syn::Member {
127 match self.member {
128 Member::Named(ident) => syn::Member::Named(ident.clone()),
129 Member::Unnamed(ref index) => syn::Member::Unnamed(index.clone()),
130 }
131 }
132
133 /// Returns `true` if this field is skipped with the given [`Trait`].
134 pub fn skip(&self, trait_: Trait) -> bool {
135 self.attr.skip.trait_skipped(trait_)
136 }
137}
138