1use proc_macro2::Span;
2
3use syn::{
4 Data, DataEnum, DataStruct, DeriveInput, Error, Fields, Generics, Ident, Index, Member, Result,
5 Type, Visibility,
6};
7
8use crate::attr::{self, Attrs};
9use crate::generics::ParamsInScope;
10
11pub enum Input<'a> {
12 Struct(Struct<'a>),
13 Enum(Enum<'a>),
14}
15
16pub enum DeriveType {
17 Error,
18 Display,
19}
20
21#[allow(dead_code)]
22pub struct Struct<'a> {
23 pub derive: DeriveType,
24 pub attrs: Attrs<'a>,
25 pub ident: Ident,
26 pub generics: &'a Generics,
27 pub fields: Vec<Field<'a>>,
28 pub vis: Visibility,
29}
30
31pub struct Enum<'a> {
32 pub derive: DeriveType,
33 pub attrs: Attrs<'a>,
34 pub ident: Ident,
35 pub generics: &'a Generics,
36 pub variants: Vec<Variant<'a>>,
37 pub vis: Visibility,
38}
39
40pub struct Variant<'a> {
41 pub original: &'a syn::Variant,
42 pub attrs: Attrs<'a>,
43 pub ident: Ident,
44 pub fields: Vec<Field<'a>>,
45}
46
47pub struct Field<'a> {
48 pub original: &'a syn::Field,
49 pub attrs: Attrs<'a>,
50 pub member: Member,
51 pub ty: &'a Type,
52 pub contains_generic: bool,
53}
54
55impl<'a> Input<'a> {
56 pub fn from_syn(node: &'a DeriveInput, derive: DeriveType) -> Result<Self> {
57 match &node.data {
58 Data::Struct(data) => Struct::from_syn(node, data, derive).map(Input::Struct),
59 Data::Enum(data) => Enum::from_syn(node, data, derive).map(Input::Enum),
60 Data::Union(_) => Err(Error::new_spanned(
61 node,
62 "union as errors are not supported",
63 )),
64 }
65 }
66}
67
68impl<'a> Struct<'a> {
69 fn from_syn(node: &'a DeriveInput, data: &'a DataStruct, derive: DeriveType) -> Result<Self> {
70 let mut attrs = attr::get(&node.attrs)?;
71 let scope = ParamsInScope::new(&node.generics);
72 let span = attrs.span().unwrap_or_else(Span::call_site);
73 let fields = Field::multiple_from_syn(&data.fields, &scope, span)?;
74 if let Some(display) = &mut attrs.display {
75 display.expand_shorthand(&fields);
76 }
77 Ok(Struct {
78 derive,
79 attrs,
80 ident: node.ident.clone(),
81 generics: &node.generics,
82 fields,
83 vis: node.vis.clone(),
84 })
85 }
86}
87
88impl<'a> Enum<'a> {
89 fn from_syn(node: &'a DeriveInput, data: &'a DataEnum, derive: DeriveType) -> Result<Self> {
90 let attrs = attr::get(&node.attrs)?;
91 let scope = ParamsInScope::new(&node.generics);
92 let span = attrs.span().unwrap_or_else(Span::call_site);
93 let variants = data
94 .variants
95 .iter()
96 .map(|node| {
97 let mut variant = Variant::from_syn(node, &scope, span)?;
98 if let display @ None = &mut variant.attrs.display {
99 display.clone_from(&attrs.display);
100 }
101 if let Some(display) = &mut variant.attrs.display {
102 display.expand_shorthand(&variant.fields);
103 } else if variant.attrs.transparent.is_none() {
104 variant.attrs.transparent = attrs.transparent;
105 }
106 Ok(variant)
107 })
108 .collect::<Result<_>>()?;
109 Ok(Enum {
110 derive,
111 attrs,
112 ident: node.ident.clone(),
113 generics: &node.generics,
114 variants,
115 vis: node.vis.clone(),
116 })
117 }
118}
119
120impl<'a> Variant<'a> {
121 fn from_syn(node: &'a syn::Variant, scope: &ParamsInScope<'a>, span: Span) -> Result<Self> {
122 let attrs = attr::get(&node.attrs)?;
123 let span = attrs.span().unwrap_or(span);
124 Ok(Variant {
125 original: node,
126 attrs,
127 ident: node.ident.clone(),
128 fields: Field::multiple_from_syn(&node.fields, scope, span)?,
129 })
130 }
131}
132
133impl<'a> Field<'a> {
134 fn multiple_from_syn(
135 fields: &'a Fields,
136 scope: &ParamsInScope<'a>,
137 span: Span,
138 ) -> Result<Vec<Self>> {
139 fields
140 .iter()
141 .enumerate()
142 .map(|(i, field)| Field::from_syn(i, field, scope, span))
143 .collect()
144 }
145
146 fn from_syn(
147 i: usize,
148 node: &'a syn::Field,
149 scope: &ParamsInScope<'a>,
150 span: Span,
151 ) -> Result<Self> {
152 Ok(Field {
153 original: node,
154 attrs: attr::get(&node.attrs)?,
155 member: node.ident.clone().map(Member::Named).unwrap_or_else(|| {
156 Member::Unnamed(Index {
157 index: i as u32,
158 span,
159 })
160 }),
161 ty: &node.ty,
162 contains_generic: scope.intersects(&node.ty),
163 })
164 }
165}
166
167impl Attrs<'_> {
168 pub fn span(&self) -> Option<Span> {
169 if let Some(display) = &self.display {
170 Some(display.fmt.span())
171 } else if let Some(transparent) = &self.transparent {
172 Some(transparent.span)
173 } else {
174 None
175 }
176 }
177}