1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
use crate::special_data::{Body, FieldsNamed, FieldsUnnamed, Special, SpecialFields};
use crate::ty::SpecialType;
use crate::unpack_context::UnpackContext;
use proc_macro2::TokenStream;
use quote::quote;
use syn::Visibility;
use crate::attributes::CompositeAttribute;
/// A trait for types that can be unpacked within the context of custom attribute processing.
///
/// Implementors of this trait can be "unpacked" to generate Rust code (as `TokenStream`)
/// based on their structure and annotations, potentially including modifications
/// influenced by a provided `UnpackContext`.
pub(crate) trait Unpack {
type Output;
/// Unpacks the current structure into a Rust `TokenStream`, taking into account
/// modifications from the given `UnpackContext` and any additional attributes.
///
/// # Parameters
/// - `self`: The instance of the implementor to unpack.
/// - `context`: The unpacking context carrying information about inherited attributes
/// and possibly influencing how unpacking is performed.
/// - `next`: A collection of `CompositeAttribute` that may modify the behavior of
/// unpacking or influence the generated output.
/// - `override_public`: A modifier that is used to force the next
/// definition to be specific publicity.
/// - `enum_context`: A boolean stating if an unnamed field is in an enum variant or not
///
/// # Returns
/// `Self::Output`: The generated Rust code as a `TokenStream`.
fn unpack(self, context: UnpackContext, next: Vec<CompositeAttribute>, override_public: Option<Visibility>, enum_context: bool) -> Self::Output;
}
impl Unpack for Special {
type Output = TokenStream;
/// Performs unpacking for `Special` structures, handling struct and enum definitions
/// uniquely based on their form and attributes.
///
/// This function combines current and inherited attributes, applies any context-specific
/// modifications, and generates a `TokenStream` representing the Rust code structure of
/// the unpacked `Special` instance.
///
/// # Parameters
/// - `self`: The `Special` instance to be unpacked.
/// - `unpack_context`: The context that may influence how unpacking is performed, including
/// attribute modifications.
/// - `Next`: Additional attributes that may come from higher-level structures or previous
/// unpacking stages, to be considered in the current unpacking process.
///
/// # Returns
/// A `TokenStream` representing the generated Rust code after unpacking.
fn unpack(self, mut unpack_context: UnpackContext, next: Vec<CompositeAttribute>, override_public: Option<Visibility>, _enum_context: bool) -> Self::Output {
// combine the attributes from the current and previous
let attrs = [self.attrs, next].concat();
let attrs = unpack_context.modify_composite(attrs);
let visibility = override_public.unwrap_or_else(|| self.vis);
let ident = self.ident; // the definition name/type
let generics = self.generics;
let where_clause = &generics.where_clause;
// based on the type of the Special type [struct | enum | union?]
// then determine the expansion
match self.body {
Body::Struct(body_struct) => match body_struct.fields {
SpecialFields::Named(named) => {
let (body, definitions) = named.unpack(unpack_context, Vec::default(), None, false);
// define our current ctx struct
// - define attributes
// - define ident and specify generics
// - insert our previous definitions behind the struct
quote!(
#(#attrs)*
#visibility struct #ident #generics #where_clause #body
#(#definitions)*
)
}
SpecialFields::Unnamed(unnamed) => {
// unpack our unnamed structure body, also collecting the recursive definitions
let (body, definitions) = unnamed.unpack(unpack_context, Vec::default(), None, false);
quote!(
#(#attrs)*
#visibility struct #ident #generics #body #where_clause;
#(#definitions)*
)
}
SpecialFields::Unit => {
// no unpacking required here, since there are no types
// in other words, this branch is always a leaf
quote!(
#(#attrs)*
#visibility struct #ident #generics;
)
}
},
Body::Enum(body_enum) => {
let mut accumulated_definitions = vec![];
let mut variants = vec![];
for variant in body_enum.variants {
let (attrs, next) = UnpackContext::filter_field_nested(variant.attrs); // todo: handle this
let ident = variant.ident;
let (field_body, mut definitions) =
variant.fields.unpack(unpack_context.clone(), next, None, true);
accumulated_definitions.append(&mut definitions);
// todo: get variant working
let discriminant = variant.discriminant;
let variant = quote!(
#(#attrs)*
#ident #field_body
#discriminant
);
variants.push(variant);
}
quote!(
#(#attrs)*
#visibility enum #ident #generics #where_clause {
#( #variants ),*
}
#(#accumulated_definitions)*
)
}
}
}
}
impl Unpack for SpecialFields {
type Output = (TokenStream, Vec<TokenStream>);
// ^body ^definitions
fn unpack(self, unpack_context: UnpackContext, next: Vec<CompositeAttribute>, _override_public: Option<Visibility>, enum_context: bool) -> Self::Output {
match self {
// Delegates to the `unpack` implementation of `FieldsNamed`, which handles the
// unpacking of named fields,
// including generating the necessary code and collecting
// any additional definitions.
SpecialFields::Named(named) => named.unpack(unpack_context, next, None, enum_context),
// Similarly, for unnamed fields (tuples), it delegates to `FieldsUnnamed`'s
// `unpack` method, which is specialized in handling tuple-like structures.
SpecialFields::Unnamed(unnamed) => unnamed.unpack(unpack_context, next, None, enum_context),
// For unit types, which have no fields, the function returns a default (empty)
// `TokenStream` along with an empty vector for definitions,
// as there's no additional
// code needed to represent a unit type in Rust.
SpecialFields::Unit => (TokenStream::default(), Vec::<TokenStream>::default()),
}
}
}
impl Unpack for FieldsNamed {
type Output = (TokenStream, Vec<TokenStream>);
// ^body ^definitions
fn unpack(self, unpack_context: UnpackContext, from_variant: Vec<CompositeAttribute>, _override_public: Option<Visibility>, enum_context: bool) -> Self::Output {
// fields buffer load each
let mut fields = vec![];
let mut definitions = vec![];
// iterate through the fields
for field in self.named {
// filter the attributes, passing the #> to the next iteration,
// we need to filter the attributes so that we can determine which are normal
// or which should be passed on
let (attrs, next) = UnpackContext::filter_field_nested(field.attrs);
let vis = field.vis;
// unused field mutability see syn doc for FieldMutability
let _mutability = field.mutability;
// this is a named type, so there should always be an ident
// if there is no ident then there should be a parsing bug
let ident = field.ident.unwrap_or_else(|| {
panic!(
"Internal Macro Error. This is a bug. \
Please Consider opening an issue with steps to reproduce the bug \
Provide this information: Error from line {}",
{ line!() }
)
});
let fish = field.fish;
// branch off the type depending on if leaf is reached
match field.ty {
// leaf node aka a non-special type => don't recurse
// `SpecialType::Type`
// doesn't need fish because it will always be None
SpecialType::Type(ty) => {
let field = quote!(
#(#attrs)*
#vis #ident : #ty
);
fields.push(field);
}
SpecialType::Augmented(augmented) => {
// combine attributes possibly inherited from an enum variant with field attrs
let next = [next, from_variant.clone()].concat();
let (ty, mut aug_definitions) = augmented.unpack(unpack_context.clone(), next, None, enum_context);
definitions.append(&mut aug_definitions);
let field = quote!(
#(#attrs)*
#vis #ident : #ty
);
fields.push(field);
}
// recuse down the parse stack
SpecialType::Def(special) => {
// trust that ty will be a definition step
let ty = &special.ident; // don't move so no clone!
// todo: add fish syntax
let field = quote!(
#(#attrs)*
#vis #ident : #ty #fish
);
fields.push(field);
// combine attributes possibly inherited from an enum variant with field attrs
let next = [next, from_variant.clone()].concat();
// unpack the definition of the type
// then add it to the definition buffer
// this could be one or more definition
// we don't care
let definition = special.unpack(unpack_context.clone(), next, None, enum_context);
definitions.push(definition);
}
}
}
let body = quote!(
{ #(#fields),* }
);
(body, definitions)
}
}
impl Unpack for FieldsUnnamed {
type Output = (TokenStream, Vec<TokenStream>);
// ^body ^definitions
fn unpack(self, unpack_context: UnpackContext, from_variant: Vec<CompositeAttribute>, _override_public: Option<Visibility>, enum_context: bool) -> Self::Output {
let mut fields = vec![];
let mut definitions = vec![];
// iterate through types
for field in self.unnamed {
// filter the attributes, passing the #> to the next iteration
let (attrs, next) = UnpackContext::filter_field_nested(field.attrs);
// let vis = field.vis;
// if we are in an enum variant then don't show the visibility to the field
let move_vis = field.vis;
let vis = if enum_context {
None
} else {
Some(&move_vis)
};
// unused field mutability see syn doc for FieldMutability
let _mutability = field.mutability;
// this is an unnamed variant so there should never Some(T)
let _ident = field.ident; // todo: warn if this is not none
let fish = field.fish;
// branch off based on if a type is defined or should be defined
match field.ty {
SpecialType::Type(ty) => {
let field = quote!(
#(#attrs)*
#vis #ty
);
fields.push(field);
}
SpecialType::Augmented(augmented) => {
// combine attributes possibly inherited from an enum variant with field attrs
let next = [next, from_variant.clone()].concat();
// if it is an unnamed field, then the definition visibility must be overridden
let override_publicity = Some(move_vis.clone());
// if field is unnamed the field publicity should be applied to the definition
let (ty, mut aug_definitions) = augmented.unpack(unpack_context.clone(), next, override_publicity, enum_context);
definitions.append(&mut aug_definitions);
let field = quote!(
#(#attrs)*
#vis #ty
);
fields.push(field);
}
SpecialType::Def(special) => {
let ty = &special.ident;
let field = quote!(
#(#attrs)*
#vis #ty #fish
);
fields.push(field);
// combine attributes possibly inherited from an enum variant with field attrs
let next = [next, from_variant.clone()].concat();
// if it is an unnamed field, then the definition visibility must be overridden
let override_publicity = Some(move_vis);
// if field is unnamed the field publicity should be applied to the definition
let definition = special.unpack(unpack_context.clone(), next, override_publicity, enum_context);
definitions.push(definition);
}
}
}
let body = quote!(
( #(#fields),* )
);
(body, definitions)
}
}