1use std::collections::BTreeMap;
2
3use proc_macro2::{Span, TokenStream};
4use syn::spanned::Spanned;
5
6use crate::internals::attr::{self, ModeIdent, ModeKind, TypeAttr};
7use crate::internals::build::Build;
8use crate::internals::name::NameAll;
9use crate::internals::tokens::Tokens;
10use crate::internals::{Ctxt, Expansion, Mode, Only, Result};
11
12#[derive(Clone, Copy)]
13pub(crate) enum UnsizedMethod {
14 Default,
15 Bytes,
16}
17
18impl UnsizedMethod {
19 pub(crate) fn as_method_name(&self) -> syn::Ident {
21 match self {
22 Self::Default => syn::Ident::new("decode_unsized", Span::call_site()),
23 Self::Bytes => syn::Ident::new("decode_unsized_bytes", Span::call_site()),
24 }
25 }
26}
27
28#[derive(Default, Clone, Copy)]
29pub(crate) enum NameMethod {
30 #[default]
32 Value,
33 Unsized(UnsizedMethod),
35}
36
37impl NameMethod {
38 pub(crate) fn name_all(&self) -> Option<NameAll> {
39 match self {
40 Self::Value => None,
41 Self::Unsized(_) => Some(NameAll::Name),
42 }
43 }
44}
45
46pub(crate) struct FieldData<'a> {
47 pub(crate) span: Span,
48 pub(crate) index: usize,
49 pub(crate) attr: attr::Field,
50 pub(crate) ident: Option<&'a syn::Ident>,
51 pub(crate) ty: &'a syn::Type,
52}
53
54pub(crate) struct StructData<'a> {
55 pub(crate) span: Span,
56 pub(crate) name: syn::LitStr,
57 pub(crate) fields: Vec<FieldData<'a>>,
58 pub(crate) kind: StructKind,
59}
60
61pub(crate) struct VariantData<'a> {
62 pub(crate) span: Span,
63 pub(crate) name: syn::LitStr,
64 pub(crate) index: usize,
65 pub(crate) attr: attr::VariantAttr,
66 pub(crate) ident: &'a syn::Ident,
67 pub(crate) fields: Vec<FieldData<'a>>,
68 pub(crate) kind: StructKind,
69}
70
71#[derive(Debug, Clone, Copy)]
72pub(crate) enum StructKind {
73 Indexed(usize),
74 Named,
75 Empty,
76}
77
78pub(crate) struct EnumData<'a> {
79 pub(crate) span: Span,
80 pub(crate) name: syn::LitStr,
81 pub(crate) variants: Vec<VariantData<'a>>,
82}
83
84pub(crate) enum Data<'a> {
85 Struct(StructData<'a>),
86 Enum(EnumData<'a>),
87 Union,
88}
89
90pub(crate) struct Expander<'a> {
91 pub(crate) input: &'a syn::DeriveInput,
92 pub(crate) cx: Ctxt,
93 pub(crate) type_attr: TypeAttr,
94 pub(crate) data: Data<'a>,
95 pub(crate) tokens: Tokens,
96 pub(crate) default: Vec<ModeIdent>,
97}
98
99impl<'a> Expander<'a> {
100 pub(crate) fn new(input: &'a syn::DeriveInput, default_crate: &str) -> Self {
101 fn fields<'a>(cx: &Ctxt, fields: &'a syn::Fields) -> Vec<FieldData<'a>> {
102 fields
103 .iter()
104 .enumerate()
105 .map(|(index, field)| FieldData {
106 span: field.span(),
107 index,
108 attr: attr::field_attrs(cx, &field.attrs),
109 ident: field.ident.as_ref(),
110 ty: &field.ty,
111 })
112 .collect()
113 }
114
115 let cx = Ctxt::new();
116 let type_attr = attr::type_attrs(&cx, &input.attrs);
117
118 let data = match &input.data {
119 syn::Data::Struct(st) => Data::Struct(StructData {
120 span: Span::call_site(),
121 name: syn::LitStr::new(&input.ident.to_string(), input.ident.span()),
122 fields: fields(&cx, &st.fields),
123 kind: match &st.fields {
124 syn::Fields::Unit => StructKind::Empty,
125 syn::Fields::Unnamed(f) => StructKind::Indexed(f.unnamed.len()),
126 syn::Fields::Named(..) => StructKind::Named,
127 },
128 }),
129 syn::Data::Enum(en) => {
130 let variants = en
131 .variants
132 .iter()
133 .enumerate()
134 .map(|(index, variant)| VariantData {
135 span: variant.span(),
136 index,
137 name: syn::LitStr::new(&variant.ident.to_string(), variant.ident.span()),
138 attr: attr::variant_attrs(&cx, &variant.attrs),
139 ident: &variant.ident,
140 fields: fields(&cx, &variant.fields),
141 kind: match &variant.fields {
142 syn::Fields::Unit => StructKind::Empty,
143 syn::Fields::Unnamed(f) => StructKind::Indexed(f.unnamed.len()),
144 syn::Fields::Named(..) => StructKind::Named,
145 },
146 });
147
148 Data::Enum(EnumData {
149 span: Span::call_site(),
150 name: syn::LitStr::new(&input.ident.to_string(), input.ident.span()),
151 variants: variants.collect(),
152 })
153 }
154 syn::Data::Union(..) => Data::Union,
155 };
156
157 let prefix = type_attr.crate_or_default(default_crate);
158
159 let default = vec![
160 ModeIdent {
161 kind: ModeKind::Binary,
162 ident: syn::Ident::new("Binary", Span::call_site()),
163 },
164 ModeIdent {
165 kind: ModeKind::Text,
166 ident: syn::Ident::new("Text", Span::call_site()),
167 },
168 ];
169
170 Self {
171 input,
172 cx,
173 type_attr,
174 data,
175 tokens: Tokens::new(input.ident.span(), prefix),
176 default,
177 }
178 }
179
180 pub(crate) fn into_errors(self) -> Vec<syn::Error> {
182 self.cx.into_errors()
183 }
184
185 fn setup_builds<'b>(&'b self, modes: &'b [ModeIdent], only: Only) -> Result<Vec<Build<'b>>> {
186 let mut builds = Vec::new();
187
188 let mut missing = BTreeMap::new();
189
190 for default in &self.default {
191 missing.insert(&default.kind, default);
192 }
193
194 for mode_ident in modes {
195 missing.remove(&mode_ident.kind);
196
197 builds.push(crate::internals::build::setup(
198 self,
199 Expansion { mode_ident },
200 only,
201 )?);
202 }
203
204 for (_, mode_ident) in missing {
205 builds.push(crate::internals::build::setup(
206 self,
207 Expansion { mode_ident },
208 only,
209 )?);
210 }
211
212 Ok(builds)
213 }
214
215 pub(crate) fn expand_encode(&self) -> Result<TokenStream> {
217 let modes = self.cx.modes();
218 let builds = self.setup_builds(&modes, Only::Encode)?;
219
220 let mut out = TokenStream::new();
221
222 for build in builds {
223 out.extend(crate::en::expand_insert_entry(build)?);
224 }
225
226 Ok(out)
227 }
228
229 pub(crate) fn expand_decode(&self) -> Result<TokenStream> {
231 let modes = self.cx.modes();
232 let builds = self.setup_builds(&modes, Only::Decode)?;
233
234 let mut out = TokenStream::new();
235
236 for build in builds {
237 out.extend(crate::de::expand_decode_entry(build)?);
238 }
239
240 Ok(out)
241 }
242}
243
244pub(crate) trait Taggable {
246 fn span(&self) -> Span;
248 fn name(&self, mode: Mode<'_>) -> Option<&(Span, syn::Expr)>;
250 fn index(&self) -> usize;
252}
253
254pub(crate) fn expand_name(
256 taggable: &dyn Taggable,
257 mode: Mode<'_>,
258 name_all: NameAll,
259 ident: Option<&syn::Ident>,
260) -> syn::Expr {
261 let lit = 'out: {
262 if let Some((_, rename)) = taggable.name(mode) {
263 return rename.clone();
264 }
265
266 if let (Some(ident), name_all) = (ident, name_all) {
267 if let Some(name) = name_all.apply(&ident.to_string()) {
268 break 'out syn::LitStr::new(&name, ident.span()).into();
269 }
270 }
271
272 usize_suffixed(taggable.index(), taggable.span()).into()
273 };
274
275 syn::Expr::Lit(syn::ExprLit {
276 attrs: Vec::new(),
277 lit,
278 })
279}
280
281pub(crate) fn usize_suffixed(index: usize, span: Span) -> syn::LitInt {
284 syn::LitInt::new(&format!("{}usize", index), span)
285}
286
287impl Taggable for FieldData<'_> {
288 fn span(&self) -> Span {
289 self.span
290 }
291
292 fn name(&self, mode: Mode<'_>) -> Option<&(Span, syn::Expr)> {
293 self.attr.name(mode)
294 }
295
296 fn index(&self) -> usize {
297 self.index
298 }
299}
300
301impl Taggable for VariantData<'_> {
302 fn span(&self) -> Span {
303 self.span
304 }
305
306 fn name(&self, mode: Mode<'_>) -> Option<&(Span, syn::Expr)> {
307 self.attr.name(mode)
308 }
309
310 fn index(&self) -> usize {
311 self.index
312 }
313}